xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp (revision 647cbc5de815c5651677bf8582797f716ec7b48d)
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 
31*647cbc5dSDimitry Andric   const BugType DebugMsgBugType{this, "Checking analyzer assumptions", "debug",
32*647cbc5dSDimitry Andric                                 /*SuppressOnSink=*/true};
335ffd83dbSDimitry Andric 
345ffd83dbSDimitry Andric   template <typename Getter>
355ffd83dbSDimitry Andric   void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
365ffd83dbSDimitry Andric                                   Getter get) const;
375ffd83dbSDimitry Andric   void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
385ffd83dbSDimitry Andric   void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
395ffd83dbSDimitry Andric   ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
405ffd83dbSDimitry Andric 
415ffd83dbSDimitry Andric   typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
425ffd83dbSDimitry Andric                                                  CheckerContext &) const;
435ffd83dbSDimitry Andric 
445ffd83dbSDimitry Andric   CallDescriptionMap<FnCheck> Callbacks = {
45bdd1243dSDimitry Andric       {{{"clang_analyzer_container_begin"}, 1},
465ffd83dbSDimitry Andric        &DebugContainerModeling::analyzerContainerBegin},
47bdd1243dSDimitry Andric       {{{"clang_analyzer_container_end"}, 1},
485ffd83dbSDimitry Andric        &DebugContainerModeling::analyzerContainerEnd},
495ffd83dbSDimitry Andric   };
505ffd83dbSDimitry Andric 
515ffd83dbSDimitry Andric public:
525ffd83dbSDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
535ffd83dbSDimitry Andric };
545ffd83dbSDimitry Andric 
555ffd83dbSDimitry Andric } //namespace
565ffd83dbSDimitry Andric 
575ffd83dbSDimitry Andric bool DebugContainerModeling::evalCall(const CallEvent &Call,
585ffd83dbSDimitry Andric                                       CheckerContext &C) const {
595ffd83dbSDimitry Andric   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
605ffd83dbSDimitry Andric   if (!CE)
615ffd83dbSDimitry Andric     return false;
625ffd83dbSDimitry Andric 
635ffd83dbSDimitry Andric   const FnCheck *Handler = Callbacks.lookup(Call);
645ffd83dbSDimitry Andric   if (!Handler)
655ffd83dbSDimitry Andric     return false;
665ffd83dbSDimitry Andric 
675ffd83dbSDimitry Andric   (this->**Handler)(CE, C);
685ffd83dbSDimitry Andric   return true;
695ffd83dbSDimitry Andric }
705ffd83dbSDimitry Andric 
715ffd83dbSDimitry Andric template <typename Getter>
725ffd83dbSDimitry Andric void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
735ffd83dbSDimitry Andric                                                         CheckerContext &C,
745ffd83dbSDimitry Andric                                                         Getter get) const {
755ffd83dbSDimitry Andric   if (CE->getNumArgs() == 0) {
765ffd83dbSDimitry Andric     reportDebugMsg("Missing container argument", C);
775ffd83dbSDimitry Andric     return;
785ffd83dbSDimitry Andric   }
795ffd83dbSDimitry Andric 
805ffd83dbSDimitry Andric   auto State = C.getState();
815ffd83dbSDimitry Andric   const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
825ffd83dbSDimitry Andric   if (Cont) {
835ffd83dbSDimitry Andric     const auto *Data = getContainerData(State, Cont);
845ffd83dbSDimitry Andric     if (Data) {
855ffd83dbSDimitry Andric       SymbolRef Field = get(Data);
865ffd83dbSDimitry Andric       if (Field) {
875ffd83dbSDimitry Andric         State = State->BindExpr(CE, C.getLocationContext(),
885ffd83dbSDimitry Andric                                 nonloc::SymbolVal(Field));
895ffd83dbSDimitry Andric 
905ffd83dbSDimitry Andric         // Progpagate interestingness from the container's data (marked
915ffd83dbSDimitry Andric         // interesting by an `ExprInspection` debug call to the container
925ffd83dbSDimitry Andric         // itself.
935ffd83dbSDimitry Andric         const NoteTag *InterestingTag =
945ffd83dbSDimitry Andric           C.getNoteTag(
955ffd83dbSDimitry Andric               [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
965ffd83dbSDimitry Andric                 if (BR.isInteresting(Field)) {
975ffd83dbSDimitry Andric                   BR.markInteresting(Cont);
985ffd83dbSDimitry Andric                 }
995ffd83dbSDimitry Andric                 return "";
1005ffd83dbSDimitry Andric               });
1015ffd83dbSDimitry Andric         C.addTransition(State, InterestingTag);
1025ffd83dbSDimitry Andric         return;
1035ffd83dbSDimitry Andric       }
1045ffd83dbSDimitry Andric     }
1055ffd83dbSDimitry Andric   }
1065ffd83dbSDimitry Andric 
1075ffd83dbSDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
1085ffd83dbSDimitry Andric   State = State->BindExpr(CE, C.getLocationContext(),
1095ffd83dbSDimitry Andric                    nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
1105ffd83dbSDimitry Andric }
1115ffd83dbSDimitry Andric 
1125ffd83dbSDimitry Andric void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
1135ffd83dbSDimitry Andric                                                     CheckerContext &C) const {
1145ffd83dbSDimitry Andric   analyzerContainerDataField(CE, C, [](const ContainerData *D) {
1155ffd83dbSDimitry Andric       return D->getBegin();
1165ffd83dbSDimitry Andric     });
1175ffd83dbSDimitry Andric }
1185ffd83dbSDimitry Andric 
1195ffd83dbSDimitry Andric void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
1205ffd83dbSDimitry Andric                                                   CheckerContext &C) const {
1215ffd83dbSDimitry Andric   analyzerContainerDataField(CE, C, [](const ContainerData *D) {
1225ffd83dbSDimitry Andric       return D->getEnd();
1235ffd83dbSDimitry Andric     });
1245ffd83dbSDimitry Andric }
1255ffd83dbSDimitry Andric 
1265ffd83dbSDimitry Andric ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
1275ffd83dbSDimitry Andric                                                      CheckerContext &C) const {
1285ffd83dbSDimitry Andric   ExplodedNode *N = C.generateNonFatalErrorNode();
1295ffd83dbSDimitry Andric   if (!N)
1305ffd83dbSDimitry Andric     return nullptr;
1315ffd83dbSDimitry Andric 
1325ffd83dbSDimitry Andric   auto &BR = C.getBugReporter();
133*647cbc5dSDimitry Andric   BR.emitReport(
134*647cbc5dSDimitry Andric       std::make_unique<PathSensitiveBugReport>(DebugMsgBugType, Msg, N));
1355ffd83dbSDimitry Andric   return N;
1365ffd83dbSDimitry Andric }
1375ffd83dbSDimitry Andric 
1385ffd83dbSDimitry Andric void ento::registerDebugContainerModeling(CheckerManager &mgr) {
1395ffd83dbSDimitry Andric   mgr.registerChecker<DebugContainerModeling>();
1405ffd83dbSDimitry Andric }
1415ffd83dbSDimitry Andric 
1425ffd83dbSDimitry Andric bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {
1435ffd83dbSDimitry Andric   return true;
1445ffd83dbSDimitry Andric }
145