xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
15ffd83dbSDimitry Andric //==-- DebugContainerModeling.cpp ---------------------------------*- C++ -*--//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // Defines a checker for debugging iterator modeling.
105ffd83dbSDimitry Andric //
115ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
125ffd83dbSDimitry Andric 
135ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
145ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
155ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
16349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
175ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
185ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
195ffd83dbSDimitry Andric 
205ffd83dbSDimitry Andric #include "Iterator.h"
215ffd83dbSDimitry Andric 
225ffd83dbSDimitry Andric using namespace clang;
235ffd83dbSDimitry Andric using namespace ento;
245ffd83dbSDimitry Andric using namespace iterator;
255ffd83dbSDimitry Andric 
265ffd83dbSDimitry Andric namespace {
275ffd83dbSDimitry Andric 
285ffd83dbSDimitry Andric class DebugContainerModeling
295ffd83dbSDimitry Andric   : public Checker<eval::Call> {
305ffd83dbSDimitry Andric 
315ffd83dbSDimitry Andric   std::unique_ptr<BugType> DebugMsgBugType;
325ffd83dbSDimitry Andric 
335ffd83dbSDimitry Andric   template <typename Getter>
345ffd83dbSDimitry Andric   void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
355ffd83dbSDimitry Andric                                   Getter get) const;
365ffd83dbSDimitry Andric   void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
375ffd83dbSDimitry Andric   void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
385ffd83dbSDimitry Andric   ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
395ffd83dbSDimitry Andric 
405ffd83dbSDimitry Andric   typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
415ffd83dbSDimitry Andric                                                  CheckerContext &) const;
425ffd83dbSDimitry Andric 
435ffd83dbSDimitry Andric   CallDescriptionMap<FnCheck> Callbacks = {
44*bdd1243dSDimitry Andric       {{{"clang_analyzer_container_begin"}, 1},
455ffd83dbSDimitry Andric        &DebugContainerModeling::analyzerContainerBegin},
46*bdd1243dSDimitry Andric       {{{"clang_analyzer_container_end"}, 1},
475ffd83dbSDimitry Andric        &DebugContainerModeling::analyzerContainerEnd},
485ffd83dbSDimitry Andric   };
495ffd83dbSDimitry Andric 
505ffd83dbSDimitry Andric public:
515ffd83dbSDimitry Andric   DebugContainerModeling();
525ffd83dbSDimitry Andric 
535ffd83dbSDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
545ffd83dbSDimitry Andric };
555ffd83dbSDimitry Andric 
565ffd83dbSDimitry Andric } //namespace
575ffd83dbSDimitry Andric 
585ffd83dbSDimitry Andric DebugContainerModeling::DebugContainerModeling() {
595ffd83dbSDimitry Andric   DebugMsgBugType.reset(
605ffd83dbSDimitry Andric       new BugType(this, "Checking analyzer assumptions", "debug",
615ffd83dbSDimitry Andric                   /*SuppressOnSink=*/true));
625ffd83dbSDimitry Andric }
635ffd83dbSDimitry Andric 
645ffd83dbSDimitry Andric bool DebugContainerModeling::evalCall(const CallEvent &Call,
655ffd83dbSDimitry Andric                                       CheckerContext &C) const {
665ffd83dbSDimitry Andric   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
675ffd83dbSDimitry Andric   if (!CE)
685ffd83dbSDimitry Andric     return false;
695ffd83dbSDimitry Andric 
705ffd83dbSDimitry Andric   const FnCheck *Handler = Callbacks.lookup(Call);
715ffd83dbSDimitry Andric   if (!Handler)
725ffd83dbSDimitry Andric     return false;
735ffd83dbSDimitry Andric 
745ffd83dbSDimitry Andric   (this->**Handler)(CE, C);
755ffd83dbSDimitry Andric   return true;
765ffd83dbSDimitry Andric }
775ffd83dbSDimitry Andric 
785ffd83dbSDimitry Andric template <typename Getter>
795ffd83dbSDimitry Andric void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
805ffd83dbSDimitry Andric                                                         CheckerContext &C,
815ffd83dbSDimitry Andric                                                         Getter get) const {
825ffd83dbSDimitry Andric   if (CE->getNumArgs() == 0) {
835ffd83dbSDimitry Andric     reportDebugMsg("Missing container argument", C);
845ffd83dbSDimitry Andric     return;
855ffd83dbSDimitry Andric   }
865ffd83dbSDimitry Andric 
875ffd83dbSDimitry Andric   auto State = C.getState();
885ffd83dbSDimitry Andric   const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
895ffd83dbSDimitry Andric   if (Cont) {
905ffd83dbSDimitry Andric     const auto *Data = getContainerData(State, Cont);
915ffd83dbSDimitry Andric     if (Data) {
925ffd83dbSDimitry Andric       SymbolRef Field = get(Data);
935ffd83dbSDimitry Andric       if (Field) {
945ffd83dbSDimitry Andric         State = State->BindExpr(CE, C.getLocationContext(),
955ffd83dbSDimitry Andric                                 nonloc::SymbolVal(Field));
965ffd83dbSDimitry Andric 
975ffd83dbSDimitry Andric         // Progpagate interestingness from the container's data (marked
985ffd83dbSDimitry Andric         // interesting by an `ExprInspection` debug call to the container
995ffd83dbSDimitry Andric         // itself.
1005ffd83dbSDimitry Andric         const NoteTag *InterestingTag =
1015ffd83dbSDimitry Andric           C.getNoteTag(
1025ffd83dbSDimitry Andric               [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
1035ffd83dbSDimitry Andric                 if (BR.isInteresting(Field)) {
1045ffd83dbSDimitry Andric                   BR.markInteresting(Cont);
1055ffd83dbSDimitry Andric                 }
1065ffd83dbSDimitry Andric                 return "";
1075ffd83dbSDimitry Andric               });
1085ffd83dbSDimitry Andric         C.addTransition(State, InterestingTag);
1095ffd83dbSDimitry Andric         return;
1105ffd83dbSDimitry Andric       }
1115ffd83dbSDimitry Andric     }
1125ffd83dbSDimitry Andric   }
1135ffd83dbSDimitry Andric 
1145ffd83dbSDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
1155ffd83dbSDimitry Andric   State = State->BindExpr(CE, C.getLocationContext(),
1165ffd83dbSDimitry Andric                    nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
1175ffd83dbSDimitry Andric }
1185ffd83dbSDimitry Andric 
1195ffd83dbSDimitry Andric void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
1205ffd83dbSDimitry Andric                                                     CheckerContext &C) const {
1215ffd83dbSDimitry Andric   analyzerContainerDataField(CE, C, [](const ContainerData *D) {
1225ffd83dbSDimitry Andric       return D->getBegin();
1235ffd83dbSDimitry Andric     });
1245ffd83dbSDimitry Andric }
1255ffd83dbSDimitry Andric 
1265ffd83dbSDimitry Andric void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
1275ffd83dbSDimitry Andric                                                   CheckerContext &C) const {
1285ffd83dbSDimitry Andric   analyzerContainerDataField(CE, C, [](const ContainerData *D) {
1295ffd83dbSDimitry Andric       return D->getEnd();
1305ffd83dbSDimitry Andric     });
1315ffd83dbSDimitry Andric }
1325ffd83dbSDimitry Andric 
1335ffd83dbSDimitry Andric ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
1345ffd83dbSDimitry Andric                                                      CheckerContext &C) const {
1355ffd83dbSDimitry Andric   ExplodedNode *N = C.generateNonFatalErrorNode();
1365ffd83dbSDimitry Andric   if (!N)
1375ffd83dbSDimitry Andric     return nullptr;
1385ffd83dbSDimitry Andric 
1395ffd83dbSDimitry Andric   auto &BR = C.getBugReporter();
1405ffd83dbSDimitry Andric   BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
1415ffd83dbSDimitry Andric                                                          Msg, N));
1425ffd83dbSDimitry Andric   return N;
1435ffd83dbSDimitry Andric }
1445ffd83dbSDimitry Andric 
1455ffd83dbSDimitry Andric void ento::registerDebugContainerModeling(CheckerManager &mgr) {
1465ffd83dbSDimitry Andric   mgr.registerChecker<DebugContainerModeling>();
1475ffd83dbSDimitry Andric }
1485ffd83dbSDimitry Andric 
1495ffd83dbSDimitry Andric bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {
1505ffd83dbSDimitry Andric   return true;
1515ffd83dbSDimitry Andric }
152