xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp (revision 024281d4d26344f9613b9115ea1fcbdbdba23235)
1811b1736SZurab Tsinadze //== InvalidPtrChecker.cpp ------------------------------------- -*- C++ -*--=//
2811b1736SZurab Tsinadze //
3811b1736SZurab Tsinadze // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4811b1736SZurab Tsinadze // See https://llvm.org/LICENSE.txt for license information.
5811b1736SZurab Tsinadze // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6811b1736SZurab Tsinadze //
7811b1736SZurab Tsinadze //===----------------------------------------------------------------------===//
8811b1736SZurab Tsinadze //
9811b1736SZurab Tsinadze // This file defines InvalidPtrChecker which finds usages of possibly
10811b1736SZurab Tsinadze // invalidated pointer.
11811b1736SZurab Tsinadze // CERT SEI Rules ENV31-C and ENV34-C
12811b1736SZurab Tsinadze // For more information see:
13811b1736SZurab Tsinadze // https://wiki.sei.cmu.edu/confluence/x/8tYxBQ
14811b1736SZurab Tsinadze // https://wiki.sei.cmu.edu/confluence/x/5NUxBQ
15811b1736SZurab Tsinadze //===----------------------------------------------------------------------===//
16811b1736SZurab Tsinadze 
17811b1736SZurab Tsinadze #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18811b1736SZurab Tsinadze #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19811b1736SZurab Tsinadze #include "clang/StaticAnalyzer/Core/Checker.h"
20811b1736SZurab Tsinadze #include "clang/StaticAnalyzer/Core/CheckerManager.h"
210b9d3a6eSBalazs Benics #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
22811b1736SZurab Tsinadze #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
23811b1736SZurab Tsinadze #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24811b1736SZurab Tsinadze 
25811b1736SZurab Tsinadze using namespace clang;
26811b1736SZurab Tsinadze using namespace ento;
27811b1736SZurab Tsinadze 
28811b1736SZurab Tsinadze namespace {
29811b1736SZurab Tsinadze 
30811b1736SZurab Tsinadze class InvalidPtrChecker
31811b1736SZurab Tsinadze     : public Checker<check::Location, check::BeginFunction, check::PostCall> {
32811b1736SZurab Tsinadze private:
33f7a46d70SEndre Fülöp   // For accurate emission of NoteTags, the BugType of this checker should have
34f7a46d70SEndre Fülöp   // a unique address.
35f7a46d70SEndre Fülöp   BugType InvalidPtrBugType{this, "Use of invalidated pointer",
36f7a46d70SEndre Fülöp                             categories::MemoryError};
37811b1736SZurab Tsinadze 
38811b1736SZurab Tsinadze   void EnvpInvalidatingCall(const CallEvent &Call, CheckerContext &C) const;
39811b1736SZurab Tsinadze 
40811b1736SZurab Tsinadze   using HandlerFn = void (InvalidPtrChecker::*)(const CallEvent &Call,
41811b1736SZurab Tsinadze                                                 CheckerContext &C) const;
42811b1736SZurab Tsinadze 
43811b1736SZurab Tsinadze   // SEI CERT ENV31-C
44f7a46d70SEndre Fülöp 
45f7a46d70SEndre Fülöp   // If set to true, consider getenv calls as invalidating operations on the
46f7a46d70SEndre Fülöp   // environment variable buffer. This is implied in the standard, but in
47f7a46d70SEndre Fülöp   // practice does not cause problems (in the commonly used environments).
48f7a46d70SEndre Fülöp   bool InvalidatingGetEnv = false;
49f7a46d70SEndre Fülöp 
50f7a46d70SEndre Fülöp   // GetEnv can be treated invalidating and non-invalidating as well.
51*024281d4SBalazs Benics   const CallDescription GetEnvCall{CDM::CLibrary, {"getenv"}, 1};
52f7a46d70SEndre Fülöp 
53811b1736SZurab Tsinadze   const CallDescriptionMap<HandlerFn> EnvpInvalidatingFunctions = {
54*024281d4SBalazs Benics       {{CDM::CLibrary, {"setenv"}, 3},
55*024281d4SBalazs Benics        &InvalidPtrChecker::EnvpInvalidatingCall},
56*024281d4SBalazs Benics       {{CDM::CLibrary, {"unsetenv"}, 1},
57*024281d4SBalazs Benics        &InvalidPtrChecker::EnvpInvalidatingCall},
58*024281d4SBalazs Benics       {{CDM::CLibrary, {"putenv"}, 1},
59*024281d4SBalazs Benics        &InvalidPtrChecker::EnvpInvalidatingCall},
60*024281d4SBalazs Benics       {{CDM::CLibrary, {"_putenv_s"}, 2},
61*024281d4SBalazs Benics        &InvalidPtrChecker::EnvpInvalidatingCall},
62*024281d4SBalazs Benics       {{CDM::CLibrary, {"_wputenv_s"}, 2},
63*024281d4SBalazs Benics        &InvalidPtrChecker::EnvpInvalidatingCall},
64811b1736SZurab Tsinadze   };
65811b1736SZurab Tsinadze 
66811b1736SZurab Tsinadze   void postPreviousReturnInvalidatingCall(const CallEvent &Call,
67811b1736SZurab Tsinadze                                           CheckerContext &C) const;
68811b1736SZurab Tsinadze 
69811b1736SZurab Tsinadze   // SEI CERT ENV34-C
70811b1736SZurab Tsinadze   const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions = {
71*024281d4SBalazs Benics       {{CDM::CLibrary, {"setlocale"}, 2},
72811b1736SZurab Tsinadze        &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
73*024281d4SBalazs Benics       {{CDM::CLibrary, {"strerror"}, 1},
74811b1736SZurab Tsinadze        &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
75*024281d4SBalazs Benics       {{CDM::CLibrary, {"localeconv"}, 0},
76d9ab3e82Sserge-sans-paille        &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
77*024281d4SBalazs Benics       {{CDM::CLibrary, {"asctime"}, 1},
78d9ab3e82Sserge-sans-paille        &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
79811b1736SZurab Tsinadze   };
80811b1736SZurab Tsinadze 
81f7a46d70SEndre Fülöp   // The private members of this checker corresponding to commandline options
82f7a46d70SEndre Fülöp   // are set in this function.
83f7a46d70SEndre Fülöp   friend void ento::registerInvalidPtrChecker(CheckerManager &);
84f7a46d70SEndre Fülöp 
85811b1736SZurab Tsinadze public:
86811b1736SZurab Tsinadze   // Obtain the environment pointer from 'main()' (if present).
87811b1736SZurab Tsinadze   void checkBeginFunction(CheckerContext &C) const;
88811b1736SZurab Tsinadze 
89811b1736SZurab Tsinadze   // Handle functions in EnvpInvalidatingFunctions, that invalidate environment
90811b1736SZurab Tsinadze   // pointer from 'main()'
91811b1736SZurab Tsinadze   // Handle functions in PreviousCallInvalidatingFunctions.
92811b1736SZurab Tsinadze   // Also, check if invalidated region is passed to a
93811b1736SZurab Tsinadze   // conservatively evaluated function call as an argument.
94811b1736SZurab Tsinadze   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
95811b1736SZurab Tsinadze 
96811b1736SZurab Tsinadze   // Check if invalidated region is being dereferenced.
97811b1736SZurab Tsinadze   void checkLocation(SVal l, bool isLoad, const Stmt *S,
98811b1736SZurab Tsinadze                      CheckerContext &C) const;
99f7a46d70SEndre Fülöp 
100f7a46d70SEndre Fülöp private:
101f7a46d70SEndre Fülöp   const NoteTag *createEnvInvalidationNote(CheckerContext &C,
102f7a46d70SEndre Fülöp                                            ProgramStateRef State,
103f7a46d70SEndre Fülöp                                            StringRef FunctionName) const;
104811b1736SZurab Tsinadze };
105811b1736SZurab Tsinadze 
106811b1736SZurab Tsinadze } // namespace
107811b1736SZurab Tsinadze 
108811b1736SZurab Tsinadze // Set of memory regions that were invalidated
REGISTER_SET_WITH_PROGRAMSTATE(InvalidMemoryRegions,const MemRegion *)109811b1736SZurab Tsinadze REGISTER_SET_WITH_PROGRAMSTATE(InvalidMemoryRegions, const MemRegion *)
110811b1736SZurab Tsinadze 
111811b1736SZurab Tsinadze // Stores the region of the environment pointer of 'main' (if present).
112f7a46d70SEndre Fülöp REGISTER_TRAIT_WITH_PROGRAMSTATE(MainEnvPtrRegion, const MemRegion *)
113f7a46d70SEndre Fülöp 
114f7a46d70SEndre Fülöp // Stores the regions of environments returned by getenv calls.
115f7a46d70SEndre Fülöp REGISTER_SET_WITH_PROGRAMSTATE(GetenvEnvPtrRegions, const MemRegion *)
116811b1736SZurab Tsinadze 
117811b1736SZurab Tsinadze // Stores key-value pairs, where key is function declaration and value is
118811b1736SZurab Tsinadze // pointer to memory region returned by previous call of this function
119811b1736SZurab Tsinadze REGISTER_MAP_WITH_PROGRAMSTATE(PreviousCallResultMap, const FunctionDecl *,
120811b1736SZurab Tsinadze                                const MemRegion *)
121811b1736SZurab Tsinadze 
122f7a46d70SEndre Fülöp const NoteTag *InvalidPtrChecker::createEnvInvalidationNote(
123f7a46d70SEndre Fülöp     CheckerContext &C, ProgramStateRef State, StringRef FunctionName) const {
124f7a46d70SEndre Fülöp 
125f7a46d70SEndre Fülöp   const MemRegion *MainRegion = State->get<MainEnvPtrRegion>();
126f7a46d70SEndre Fülöp   const auto GetenvRegions = State->get<GetenvEnvPtrRegions>();
127f7a46d70SEndre Fülöp 
128f7a46d70SEndre Fülöp   return C.getNoteTag([this, MainRegion, GetenvRegions,
129f7a46d70SEndre Fülöp                        FunctionName = std::string{FunctionName}](
130f7a46d70SEndre Fülöp                           PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
131f7a46d70SEndre Fülöp     // Only handle the BugType of this checker.
132f7a46d70SEndre Fülöp     if (&BR.getBugType() != &InvalidPtrBugType)
133f7a46d70SEndre Fülöp       return;
134f7a46d70SEndre Fülöp 
135f7a46d70SEndre Fülöp     // Mark all regions that were interesting before as NOT interesting now
136f7a46d70SEndre Fülöp     // to avoid extra notes coming from invalidation points higher up the
137f7a46d70SEndre Fülöp     // bugpath. This ensures that only the last invalidation point is marked
138f7a46d70SEndre Fülöp     // with a note tag.
139f7a46d70SEndre Fülöp     llvm::SmallVector<std::string, 2> InvalidLocationNames;
140f7a46d70SEndre Fülöp     if (BR.isInteresting(MainRegion)) {
141f7a46d70SEndre Fülöp       BR.markNotInteresting(MainRegion);
142f7a46d70SEndre Fülöp       InvalidLocationNames.push_back("the environment parameter of 'main'");
143f7a46d70SEndre Fülöp     }
144f7a46d70SEndre Fülöp     bool InterestingGetenvFound = false;
145f7a46d70SEndre Fülöp     for (const MemRegion *MR : GetenvRegions) {
146f7a46d70SEndre Fülöp       if (BR.isInteresting(MR)) {
147f7a46d70SEndre Fülöp         BR.markNotInteresting(MR);
148f7a46d70SEndre Fülöp         if (!InterestingGetenvFound) {
149f7a46d70SEndre Fülöp           InterestingGetenvFound = true;
150f7a46d70SEndre Fülöp           InvalidLocationNames.push_back(
151f7a46d70SEndre Fülöp               "the environment returned by 'getenv'");
152f7a46d70SEndre Fülöp         }
153f7a46d70SEndre Fülöp       }
154f7a46d70SEndre Fülöp     }
155f7a46d70SEndre Fülöp 
156f7a46d70SEndre Fülöp     // Emit note tag message.
157f7a46d70SEndre Fülöp     if (InvalidLocationNames.size() >= 1)
158f7a46d70SEndre Fülöp       Out << '\'' << FunctionName << "' call may invalidate "
159f7a46d70SEndre Fülöp           << InvalidLocationNames[0];
160f7a46d70SEndre Fülöp     if (InvalidLocationNames.size() == 2)
161f7a46d70SEndre Fülöp       Out << ", and " << InvalidLocationNames[1];
162f7a46d70SEndre Fülöp   });
163f7a46d70SEndre Fülöp }
164f7a46d70SEndre Fülöp 
EnvpInvalidatingCall(const CallEvent & Call,CheckerContext & C) const165811b1736SZurab Tsinadze void InvalidPtrChecker::EnvpInvalidatingCall(const CallEvent &Call,
166811b1736SZurab Tsinadze                                              CheckerContext &C) const {
167f7a46d70SEndre Fülöp   // This callevent invalidates all previously generated pointers to the
168f7a46d70SEndre Fülöp   // environment.
169811b1736SZurab Tsinadze   ProgramStateRef State = C.getState();
170f7a46d70SEndre Fülöp   if (const MemRegion *MainEnvPtr = State->get<MainEnvPtrRegion>())
171f7a46d70SEndre Fülöp     State = State->add<InvalidMemoryRegions>(MainEnvPtr);
172f7a46d70SEndre Fülöp   for (const MemRegion *EnvPtr : State->get<GetenvEnvPtrRegions>())
173f7a46d70SEndre Fülöp     State = State->add<InvalidMemoryRegions>(EnvPtr);
174811b1736SZurab Tsinadze 
175f7a46d70SEndre Fülöp   StringRef FunctionName = Call.getCalleeIdentifier()->getName();
176f7a46d70SEndre Fülöp   const NoteTag *InvalidationNote =
177f7a46d70SEndre Fülöp       createEnvInvalidationNote(C, State, FunctionName);
178811b1736SZurab Tsinadze 
179f7a46d70SEndre Fülöp   C.addTransition(State, InvalidationNote);
180811b1736SZurab Tsinadze }
181811b1736SZurab Tsinadze 
postPreviousReturnInvalidatingCall(const CallEvent & Call,CheckerContext & C) const182811b1736SZurab Tsinadze void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
183811b1736SZurab Tsinadze     const CallEvent &Call, CheckerContext &C) const {
184811b1736SZurab Tsinadze   ProgramStateRef State = C.getState();
185811b1736SZurab Tsinadze 
186811b1736SZurab Tsinadze   const NoteTag *Note = nullptr;
187811b1736SZurab Tsinadze   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
188811b1736SZurab Tsinadze   // Invalidate the region of the previously returned pointer - if there was
189811b1736SZurab Tsinadze   // one.
190811b1736SZurab Tsinadze   if (const MemRegion *const *Reg = State->get<PreviousCallResultMap>(FD)) {
191811b1736SZurab Tsinadze     const MemRegion *PrevReg = *Reg;
192811b1736SZurab Tsinadze     State = State->add<InvalidMemoryRegions>(PrevReg);
193f7a46d70SEndre Fülöp     Note = C.getNoteTag([this, PrevReg, FD](PathSensitiveBugReport &BR,
194811b1736SZurab Tsinadze                                             llvm::raw_ostream &Out) {
195f7a46d70SEndre Fülöp       if (!BR.isInteresting(PrevReg) || &BR.getBugType() != &InvalidPtrBugType)
196811b1736SZurab Tsinadze         return;
197811b1736SZurab Tsinadze       Out << '\'';
198811b1736SZurab Tsinadze       FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true);
19987a55137SBrian Tracy       Out << "' call may invalidate the result of the previous " << '\'';
200811b1736SZurab Tsinadze       FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true);
201811b1736SZurab Tsinadze       Out << '\'';
202811b1736SZurab Tsinadze     });
203811b1736SZurab Tsinadze   }
204811b1736SZurab Tsinadze 
205811b1736SZurab Tsinadze   const LocationContext *LCtx = C.getLocationContext();
206811b1736SZurab Tsinadze   const auto *CE = cast<CallExpr>(Call.getOriginExpr());
207811b1736SZurab Tsinadze 
208811b1736SZurab Tsinadze   // Function call will return a pointer to the new symbolic region.
209811b1736SZurab Tsinadze   DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal(
210811b1736SZurab Tsinadze       CE, LCtx, CE->getType(), C.blockCount());
211811b1736SZurab Tsinadze   State = State->BindExpr(CE, LCtx, RetVal);
212811b1736SZurab Tsinadze 
213e096c144SBalazs Benics   const auto *SymRegOfRetVal =
214e096c144SBalazs Benics       dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
215e096c144SBalazs Benics   if (!SymRegOfRetVal)
216e096c144SBalazs Benics     return;
217e096c144SBalazs Benics 
218811b1736SZurab Tsinadze   // Remember to this region.
219f7a46d70SEndre Fülöp   const MemRegion *MR = SymRegOfRetVal->getBaseRegion();
220811b1736SZurab Tsinadze   State = State->set<PreviousCallResultMap>(FD, MR);
221811b1736SZurab Tsinadze 
222811b1736SZurab Tsinadze   ExplodedNode *Node = C.addTransition(State, Note);
223f7a46d70SEndre Fülöp   const NoteTag *PreviousCallNote = C.getNoteTag(
224f7a46d70SEndre Fülöp       [this, MR](PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
225f7a46d70SEndre Fülöp         if (!BR.isInteresting(MR) || &BR.getBugType() != &InvalidPtrBugType)
226811b1736SZurab Tsinadze           return;
227f7a46d70SEndre Fülöp         Out << "previous function call was here";
228811b1736SZurab Tsinadze       });
229811b1736SZurab Tsinadze 
230811b1736SZurab Tsinadze   C.addTransition(State, Node, PreviousCallNote);
231811b1736SZurab Tsinadze }
232811b1736SZurab Tsinadze 
233811b1736SZurab Tsinadze // TODO: This seems really ugly. Simplify this.
findInvalidatedSymbolicBase(ProgramStateRef State,const MemRegion * Reg)234811b1736SZurab Tsinadze static const MemRegion *findInvalidatedSymbolicBase(ProgramStateRef State,
235811b1736SZurab Tsinadze                                                     const MemRegion *Reg) {
236811b1736SZurab Tsinadze   while (Reg) {
237811b1736SZurab Tsinadze     if (State->contains<InvalidMemoryRegions>(Reg))
238811b1736SZurab Tsinadze       return Reg;
239811b1736SZurab Tsinadze     const auto *SymBase = Reg->getSymbolicBase();
240811b1736SZurab Tsinadze     if (!SymBase)
241811b1736SZurab Tsinadze       break;
242811b1736SZurab Tsinadze     const auto *SRV = dyn_cast<SymbolRegionValue>(SymBase->getSymbol());
243811b1736SZurab Tsinadze     if (!SRV)
244811b1736SZurab Tsinadze       break;
245811b1736SZurab Tsinadze     Reg = SRV->getRegion();
246811b1736SZurab Tsinadze     if (const auto *VarReg = dyn_cast<VarRegion>(SRV->getRegion()))
247811b1736SZurab Tsinadze       Reg = VarReg;
248811b1736SZurab Tsinadze   }
249811b1736SZurab Tsinadze   return nullptr;
250811b1736SZurab Tsinadze }
251811b1736SZurab Tsinadze 
252811b1736SZurab Tsinadze // Handle functions in EnvpInvalidatingFunctions, that invalidate environment
253811b1736SZurab Tsinadze // pointer from 'main()' Also, check if invalidated region is passed to a
254811b1736SZurab Tsinadze // function call as an argument.
checkPostCall(const CallEvent & Call,CheckerContext & C) const255811b1736SZurab Tsinadze void InvalidPtrChecker::checkPostCall(const CallEvent &Call,
256811b1736SZurab Tsinadze                                       CheckerContext &C) const {
257f7a46d70SEndre Fülöp 
258f7a46d70SEndre Fülöp   ProgramStateRef State = C.getState();
259f7a46d70SEndre Fülöp 
260f7a46d70SEndre Fülöp   // Model 'getenv' calls
261f7a46d70SEndre Fülöp   if (GetEnvCall.matches(Call)) {
262f7a46d70SEndre Fülöp     const MemRegion *Region = Call.getReturnValue().getAsRegion();
263f7a46d70SEndre Fülöp     if (Region) {
264f7a46d70SEndre Fülöp       State = State->add<GetenvEnvPtrRegions>(Region);
265f7a46d70SEndre Fülöp       C.addTransition(State);
266f7a46d70SEndre Fülöp     }
267f7a46d70SEndre Fülöp   }
268f7a46d70SEndre Fülöp 
269811b1736SZurab Tsinadze   // Check if function invalidates 'envp' argument of 'main'
270811b1736SZurab Tsinadze   if (const auto *Handler = EnvpInvalidatingFunctions.lookup(Call))
271811b1736SZurab Tsinadze     (this->**Handler)(Call, C);
272811b1736SZurab Tsinadze 
273811b1736SZurab Tsinadze   // Check if function invalidates the result of previous call
274811b1736SZurab Tsinadze   if (const auto *Handler = PreviousCallInvalidatingFunctions.lookup(Call))
275811b1736SZurab Tsinadze     (this->**Handler)(Call, C);
276811b1736SZurab Tsinadze 
277f7a46d70SEndre Fülöp   // If pedantic mode is on, regard 'getenv' calls invalidating as well
278f7a46d70SEndre Fülöp   if (InvalidatingGetEnv && GetEnvCall.matches(Call))
279f7a46d70SEndre Fülöp     postPreviousReturnInvalidatingCall(Call, C);
280f7a46d70SEndre Fülöp 
281811b1736SZurab Tsinadze   // Check if one of the arguments of the function call is invalidated
282811b1736SZurab Tsinadze 
283811b1736SZurab Tsinadze   // If call was inlined, don't report invalidated argument
284811b1736SZurab Tsinadze   if (C.wasInlined)
285811b1736SZurab Tsinadze     return;
286811b1736SZurab Tsinadze 
287811b1736SZurab Tsinadze   for (unsigned I = 0, NumArgs = Call.getNumArgs(); I < NumArgs; ++I) {
288811b1736SZurab Tsinadze 
289811b1736SZurab Tsinadze     if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(
290811b1736SZurab Tsinadze             Call.getArgSVal(I).getAsRegion())) {
291811b1736SZurab Tsinadze       if (const MemRegion *InvalidatedSymbolicBase =
292811b1736SZurab Tsinadze               findInvalidatedSymbolicBase(State, SR)) {
293811b1736SZurab Tsinadze         ExplodedNode *ErrorNode = C.generateNonFatalErrorNode();
294811b1736SZurab Tsinadze         if (!ErrorNode)
295811b1736SZurab Tsinadze           return;
296811b1736SZurab Tsinadze 
297811b1736SZurab Tsinadze         SmallString<256> Msg;
298811b1736SZurab Tsinadze         llvm::raw_svector_ostream Out(Msg);
299811b1736SZurab Tsinadze         Out << "use of invalidated pointer '";
300811b1736SZurab Tsinadze         Call.getArgExpr(I)->printPretty(Out, /*Helper=*/nullptr,
301811b1736SZurab Tsinadze                                         C.getASTContext().getPrintingPolicy());
302811b1736SZurab Tsinadze         Out << "' in a function call";
303811b1736SZurab Tsinadze 
304f7a46d70SEndre Fülöp         auto Report = std::make_unique<PathSensitiveBugReport>(
305f7a46d70SEndre Fülöp             InvalidPtrBugType, Out.str(), ErrorNode);
306811b1736SZurab Tsinadze         Report->markInteresting(InvalidatedSymbolicBase);
307811b1736SZurab Tsinadze         Report->addRange(Call.getArgSourceRange(I));
308811b1736SZurab Tsinadze         C.emitReport(std::move(Report));
309811b1736SZurab Tsinadze       }
310811b1736SZurab Tsinadze     }
311811b1736SZurab Tsinadze   }
312811b1736SZurab Tsinadze }
313811b1736SZurab Tsinadze 
314811b1736SZurab Tsinadze // Obtain the environment pointer from 'main()', if present.
checkBeginFunction(CheckerContext & C) const315811b1736SZurab Tsinadze void InvalidPtrChecker::checkBeginFunction(CheckerContext &C) const {
316811b1736SZurab Tsinadze   if (!C.inTopFrame())
317811b1736SZurab Tsinadze     return;
318811b1736SZurab Tsinadze 
319811b1736SZurab Tsinadze   const auto *FD = dyn_cast<FunctionDecl>(C.getLocationContext()->getDecl());
320811b1736SZurab Tsinadze   if (!FD || FD->param_size() != 3 || !FD->isMain())
321811b1736SZurab Tsinadze     return;
322811b1736SZurab Tsinadze 
323811b1736SZurab Tsinadze   ProgramStateRef State = C.getState();
324811b1736SZurab Tsinadze   const MemRegion *EnvpReg =
325811b1736SZurab Tsinadze       State->getRegion(FD->parameters()[2], C.getLocationContext());
326811b1736SZurab Tsinadze 
327811b1736SZurab Tsinadze   // Save the memory region pointed by the environment pointer parameter of
328811b1736SZurab Tsinadze   // 'main'.
329f7a46d70SEndre Fülöp   C.addTransition(State->set<MainEnvPtrRegion>(EnvpReg));
330811b1736SZurab Tsinadze }
331811b1736SZurab Tsinadze 
332811b1736SZurab Tsinadze // Check if invalidated region is being dereferenced.
checkLocation(SVal Loc,bool isLoad,const Stmt * S,CheckerContext & C) const333811b1736SZurab Tsinadze void InvalidPtrChecker::checkLocation(SVal Loc, bool isLoad, const Stmt *S,
334811b1736SZurab Tsinadze                                       CheckerContext &C) const {
335811b1736SZurab Tsinadze   ProgramStateRef State = C.getState();
336811b1736SZurab Tsinadze 
337811b1736SZurab Tsinadze   // Ignore memory operations involving 'non-invalidated' locations.
338811b1736SZurab Tsinadze   const MemRegion *InvalidatedSymbolicBase =
339811b1736SZurab Tsinadze       findInvalidatedSymbolicBase(State, Loc.getAsRegion());
340811b1736SZurab Tsinadze   if (!InvalidatedSymbolicBase)
341811b1736SZurab Tsinadze     return;
342811b1736SZurab Tsinadze 
343811b1736SZurab Tsinadze   ExplodedNode *ErrorNode = C.generateNonFatalErrorNode();
344811b1736SZurab Tsinadze   if (!ErrorNode)
345811b1736SZurab Tsinadze     return;
346811b1736SZurab Tsinadze 
347811b1736SZurab Tsinadze   auto Report = std::make_unique<PathSensitiveBugReport>(
348f7a46d70SEndre Fülöp       InvalidPtrBugType, "dereferencing an invalid pointer", ErrorNode);
349811b1736SZurab Tsinadze   Report->markInteresting(InvalidatedSymbolicBase);
350811b1736SZurab Tsinadze   C.emitReport(std::move(Report));
351811b1736SZurab Tsinadze }
352811b1736SZurab Tsinadze 
registerInvalidPtrChecker(CheckerManager & Mgr)353811b1736SZurab Tsinadze void ento::registerInvalidPtrChecker(CheckerManager &Mgr) {
354f7a46d70SEndre Fülöp   auto *Checker = Mgr.registerChecker<InvalidPtrChecker>();
355f7a46d70SEndre Fülöp   Checker->InvalidatingGetEnv =
356f7a46d70SEndre Fülöp       Mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker,
357f7a46d70SEndre Fülöp                                                        "InvalidatingGetEnv");
358811b1736SZurab Tsinadze }
359811b1736SZurab Tsinadze 
shouldRegisterInvalidPtrChecker(const CheckerManager &)360811b1736SZurab Tsinadze bool ento::shouldRegisterInvalidPtrChecker(const CheckerManager &) {
361811b1736SZurab Tsinadze   return true;
362811b1736SZurab Tsinadze }
363