xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1349cc55cSDimitry Andric //== InvalidPtrChecker.cpp ------------------------------------- -*- C++ -*--=//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric //
9349cc55cSDimitry Andric // This file defines InvalidPtrChecker which finds usages of possibly
10349cc55cSDimitry Andric // invalidated pointer.
11349cc55cSDimitry Andric // CERT SEI Rules ENV31-C and ENV34-C
12349cc55cSDimitry Andric // For more information see:
13349cc55cSDimitry Andric // https://wiki.sei.cmu.edu/confluence/x/8tYxBQ
14349cc55cSDimitry Andric // https://wiki.sei.cmu.edu/confluence/x/5NUxBQ
15349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
16349cc55cSDimitry Andric 
17349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
20349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
21349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
22349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
23349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24349cc55cSDimitry Andric 
25349cc55cSDimitry Andric using namespace clang;
26349cc55cSDimitry Andric using namespace ento;
27349cc55cSDimitry Andric 
28349cc55cSDimitry Andric namespace {
29349cc55cSDimitry Andric 
30349cc55cSDimitry Andric class InvalidPtrChecker
31349cc55cSDimitry Andric     : public Checker<check::Location, check::BeginFunction, check::PostCall> {
32349cc55cSDimitry Andric private:
335f757f3fSDimitry Andric   // For accurate emission of NoteTags, the BugType of this checker should have
345f757f3fSDimitry Andric   // a unique address.
355f757f3fSDimitry Andric   BugType InvalidPtrBugType{this, "Use of invalidated pointer",
365f757f3fSDimitry Andric                             categories::MemoryError};
37349cc55cSDimitry Andric 
38349cc55cSDimitry Andric   void EnvpInvalidatingCall(const CallEvent &Call, CheckerContext &C) const;
39349cc55cSDimitry Andric 
40349cc55cSDimitry Andric   using HandlerFn = void (InvalidPtrChecker::*)(const CallEvent &Call,
41349cc55cSDimitry Andric                                                 CheckerContext &C) const;
42349cc55cSDimitry Andric 
43349cc55cSDimitry Andric   // SEI CERT ENV31-C
445f757f3fSDimitry Andric 
455f757f3fSDimitry Andric   // If set to true, consider getenv calls as invalidating operations on the
465f757f3fSDimitry Andric   // environment variable buffer. This is implied in the standard, but in
475f757f3fSDimitry Andric   // practice does not cause problems (in the commonly used environments).
485f757f3fSDimitry Andric   bool InvalidatingGetEnv = false;
495f757f3fSDimitry Andric 
505f757f3fSDimitry Andric   // GetEnv can be treated invalidating and non-invalidating as well.
51*0fca6ea1SDimitry Andric   const CallDescription GetEnvCall{CDM::CLibrary, {"getenv"}, 1};
525f757f3fSDimitry Andric 
53349cc55cSDimitry Andric   const CallDescriptionMap<HandlerFn> EnvpInvalidatingFunctions = {
54*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"setenv"}, 3},
55*0fca6ea1SDimitry Andric        &InvalidPtrChecker::EnvpInvalidatingCall},
56*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"unsetenv"}, 1},
57*0fca6ea1SDimitry Andric        &InvalidPtrChecker::EnvpInvalidatingCall},
58*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"putenv"}, 1},
59*0fca6ea1SDimitry Andric        &InvalidPtrChecker::EnvpInvalidatingCall},
60*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"_putenv_s"}, 2},
61*0fca6ea1SDimitry Andric        &InvalidPtrChecker::EnvpInvalidatingCall},
62*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"_wputenv_s"}, 2},
63*0fca6ea1SDimitry Andric        &InvalidPtrChecker::EnvpInvalidatingCall},
64349cc55cSDimitry Andric   };
65349cc55cSDimitry Andric 
66349cc55cSDimitry Andric   void postPreviousReturnInvalidatingCall(const CallEvent &Call,
67349cc55cSDimitry Andric                                           CheckerContext &C) const;
68349cc55cSDimitry Andric 
69349cc55cSDimitry Andric   // SEI CERT ENV34-C
70349cc55cSDimitry Andric   const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions = {
71*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"setlocale"}, 2},
72349cc55cSDimitry Andric        &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
73*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"strerror"}, 1},
74349cc55cSDimitry Andric        &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
75*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"localeconv"}, 0},
76bdd1243dSDimitry Andric        &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
77*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"asctime"}, 1},
78bdd1243dSDimitry Andric        &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
79349cc55cSDimitry Andric   };
80349cc55cSDimitry Andric 
815f757f3fSDimitry Andric   // The private members of this checker corresponding to commandline options
825f757f3fSDimitry Andric   // are set in this function.
835f757f3fSDimitry Andric   friend void ento::registerInvalidPtrChecker(CheckerManager &);
845f757f3fSDimitry Andric 
85349cc55cSDimitry Andric public:
86349cc55cSDimitry Andric   // Obtain the environment pointer from 'main()' (if present).
87349cc55cSDimitry Andric   void checkBeginFunction(CheckerContext &C) const;
88349cc55cSDimitry Andric 
89349cc55cSDimitry Andric   // Handle functions in EnvpInvalidatingFunctions, that invalidate environment
90349cc55cSDimitry Andric   // pointer from 'main()'
91349cc55cSDimitry Andric   // Handle functions in PreviousCallInvalidatingFunctions.
92349cc55cSDimitry Andric   // Also, check if invalidated region is passed to a
93349cc55cSDimitry Andric   // conservatively evaluated function call as an argument.
94349cc55cSDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
95349cc55cSDimitry Andric 
96349cc55cSDimitry Andric   // Check if invalidated region is being dereferenced.
97349cc55cSDimitry Andric   void checkLocation(SVal l, bool isLoad, const Stmt *S,
98349cc55cSDimitry Andric                      CheckerContext &C) const;
995f757f3fSDimitry Andric 
1005f757f3fSDimitry Andric private:
1015f757f3fSDimitry Andric   const NoteTag *createEnvInvalidationNote(CheckerContext &C,
1025f757f3fSDimitry Andric                                            ProgramStateRef State,
1035f757f3fSDimitry Andric                                            StringRef FunctionName) const;
104349cc55cSDimitry Andric };
105349cc55cSDimitry Andric 
106349cc55cSDimitry Andric } // namespace
107349cc55cSDimitry Andric 
108349cc55cSDimitry Andric // Set of memory regions that were invalidated
109349cc55cSDimitry Andric REGISTER_SET_WITH_PROGRAMSTATE(InvalidMemoryRegions, const MemRegion *)
110349cc55cSDimitry Andric 
111349cc55cSDimitry Andric // Stores the region of the environment pointer of 'main' (if present).
1125f757f3fSDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(MainEnvPtrRegion, const MemRegion *)
1135f757f3fSDimitry Andric 
1145f757f3fSDimitry Andric // Stores the regions of environments returned by getenv calls.
1155f757f3fSDimitry Andric REGISTER_SET_WITH_PROGRAMSTATE(GetenvEnvPtrRegions, const MemRegion *)
116349cc55cSDimitry Andric 
117349cc55cSDimitry Andric // Stores key-value pairs, where key is function declaration and value is
118349cc55cSDimitry Andric // pointer to memory region returned by previous call of this function
119349cc55cSDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(PreviousCallResultMap, const FunctionDecl *,
120349cc55cSDimitry Andric                                const MemRegion *)
121349cc55cSDimitry Andric 
1225f757f3fSDimitry Andric const NoteTag *InvalidPtrChecker::createEnvInvalidationNote(
1235f757f3fSDimitry Andric     CheckerContext &C, ProgramStateRef State, StringRef FunctionName) const {
1245f757f3fSDimitry Andric 
1255f757f3fSDimitry Andric   const MemRegion *MainRegion = State->get<MainEnvPtrRegion>();
1265f757f3fSDimitry Andric   const auto GetenvRegions = State->get<GetenvEnvPtrRegions>();
1275f757f3fSDimitry Andric 
1285f757f3fSDimitry Andric   return C.getNoteTag([this, MainRegion, GetenvRegions,
1295f757f3fSDimitry Andric                        FunctionName = std::string{FunctionName}](
1305f757f3fSDimitry Andric                           PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
1315f757f3fSDimitry Andric     // Only handle the BugType of this checker.
1325f757f3fSDimitry Andric     if (&BR.getBugType() != &InvalidPtrBugType)
1335f757f3fSDimitry Andric       return;
1345f757f3fSDimitry Andric 
1355f757f3fSDimitry Andric     // Mark all regions that were interesting before as NOT interesting now
1365f757f3fSDimitry Andric     // to avoid extra notes coming from invalidation points higher up the
1375f757f3fSDimitry Andric     // bugpath. This ensures that only the last invalidation point is marked
1385f757f3fSDimitry Andric     // with a note tag.
1395f757f3fSDimitry Andric     llvm::SmallVector<std::string, 2> InvalidLocationNames;
1405f757f3fSDimitry Andric     if (BR.isInteresting(MainRegion)) {
1415f757f3fSDimitry Andric       BR.markNotInteresting(MainRegion);
1425f757f3fSDimitry Andric       InvalidLocationNames.push_back("the environment parameter of 'main'");
1435f757f3fSDimitry Andric     }
1445f757f3fSDimitry Andric     bool InterestingGetenvFound = false;
1455f757f3fSDimitry Andric     for (const MemRegion *MR : GetenvRegions) {
1465f757f3fSDimitry Andric       if (BR.isInteresting(MR)) {
1475f757f3fSDimitry Andric         BR.markNotInteresting(MR);
1485f757f3fSDimitry Andric         if (!InterestingGetenvFound) {
1495f757f3fSDimitry Andric           InterestingGetenvFound = true;
1505f757f3fSDimitry Andric           InvalidLocationNames.push_back(
1515f757f3fSDimitry Andric               "the environment returned by 'getenv'");
1525f757f3fSDimitry Andric         }
1535f757f3fSDimitry Andric       }
1545f757f3fSDimitry Andric     }
1555f757f3fSDimitry Andric 
1565f757f3fSDimitry Andric     // Emit note tag message.
1575f757f3fSDimitry Andric     if (InvalidLocationNames.size() >= 1)
1585f757f3fSDimitry Andric       Out << '\'' << FunctionName << "' call may invalidate "
1595f757f3fSDimitry Andric           << InvalidLocationNames[0];
1605f757f3fSDimitry Andric     if (InvalidLocationNames.size() == 2)
1615f757f3fSDimitry Andric       Out << ", and " << InvalidLocationNames[1];
1625f757f3fSDimitry Andric   });
1635f757f3fSDimitry Andric }
1645f757f3fSDimitry Andric 
165349cc55cSDimitry Andric void InvalidPtrChecker::EnvpInvalidatingCall(const CallEvent &Call,
166349cc55cSDimitry Andric                                              CheckerContext &C) const {
1675f757f3fSDimitry Andric   // This callevent invalidates all previously generated pointers to the
1685f757f3fSDimitry Andric   // environment.
169349cc55cSDimitry Andric   ProgramStateRef State = C.getState();
1705f757f3fSDimitry Andric   if (const MemRegion *MainEnvPtr = State->get<MainEnvPtrRegion>())
1715f757f3fSDimitry Andric     State = State->add<InvalidMemoryRegions>(MainEnvPtr);
1725f757f3fSDimitry Andric   for (const MemRegion *EnvPtr : State->get<GetenvEnvPtrRegions>())
1735f757f3fSDimitry Andric     State = State->add<InvalidMemoryRegions>(EnvPtr);
174349cc55cSDimitry Andric 
1755f757f3fSDimitry Andric   StringRef FunctionName = Call.getCalleeIdentifier()->getName();
1765f757f3fSDimitry Andric   const NoteTag *InvalidationNote =
1775f757f3fSDimitry Andric       createEnvInvalidationNote(C, State, FunctionName);
178349cc55cSDimitry Andric 
1795f757f3fSDimitry Andric   C.addTransition(State, InvalidationNote);
180349cc55cSDimitry Andric }
181349cc55cSDimitry Andric 
182349cc55cSDimitry Andric void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
183349cc55cSDimitry Andric     const CallEvent &Call, CheckerContext &C) const {
184349cc55cSDimitry Andric   ProgramStateRef State = C.getState();
185349cc55cSDimitry Andric 
186349cc55cSDimitry Andric   const NoteTag *Note = nullptr;
187349cc55cSDimitry Andric   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
188349cc55cSDimitry Andric   // Invalidate the region of the previously returned pointer - if there was
189349cc55cSDimitry Andric   // one.
190349cc55cSDimitry Andric   if (const MemRegion *const *Reg = State->get<PreviousCallResultMap>(FD)) {
191349cc55cSDimitry Andric     const MemRegion *PrevReg = *Reg;
192349cc55cSDimitry Andric     State = State->add<InvalidMemoryRegions>(PrevReg);
1935f757f3fSDimitry Andric     Note = C.getNoteTag([this, PrevReg, FD](PathSensitiveBugReport &BR,
194349cc55cSDimitry Andric                                             llvm::raw_ostream &Out) {
1955f757f3fSDimitry Andric       if (!BR.isInteresting(PrevReg) || &BR.getBugType() != &InvalidPtrBugType)
196349cc55cSDimitry Andric         return;
197349cc55cSDimitry Andric       Out << '\'';
198349cc55cSDimitry Andric       FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true);
19981ad6265SDimitry Andric       Out << "' call may invalidate the result of the previous " << '\'';
200349cc55cSDimitry Andric       FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true);
201349cc55cSDimitry Andric       Out << '\'';
202349cc55cSDimitry Andric     });
203349cc55cSDimitry Andric   }
204349cc55cSDimitry Andric 
205349cc55cSDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
206349cc55cSDimitry Andric   const auto *CE = cast<CallExpr>(Call.getOriginExpr());
207349cc55cSDimitry Andric 
208349cc55cSDimitry Andric   // Function call will return a pointer to the new symbolic region.
209349cc55cSDimitry Andric   DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal(
210349cc55cSDimitry Andric       CE, LCtx, CE->getType(), C.blockCount());
211349cc55cSDimitry Andric   State = State->BindExpr(CE, LCtx, RetVal);
212349cc55cSDimitry Andric 
2135678d1d9SDimitry Andric   const auto *SymRegOfRetVal =
2145678d1d9SDimitry Andric       dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
2155678d1d9SDimitry Andric   if (!SymRegOfRetVal)
2165678d1d9SDimitry Andric     return;
2175678d1d9SDimitry Andric 
218349cc55cSDimitry Andric   // Remember to this region.
2195f757f3fSDimitry Andric   const MemRegion *MR = SymRegOfRetVal->getBaseRegion();
220349cc55cSDimitry Andric   State = State->set<PreviousCallResultMap>(FD, MR);
221349cc55cSDimitry Andric 
222349cc55cSDimitry Andric   ExplodedNode *Node = C.addTransition(State, Note);
2235f757f3fSDimitry Andric   const NoteTag *PreviousCallNote = C.getNoteTag(
2245f757f3fSDimitry Andric       [this, MR](PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
2255f757f3fSDimitry Andric         if (!BR.isInteresting(MR) || &BR.getBugType() != &InvalidPtrBugType)
226349cc55cSDimitry Andric           return;
2275f757f3fSDimitry Andric         Out << "previous function call was here";
228349cc55cSDimitry Andric       });
229349cc55cSDimitry Andric 
230349cc55cSDimitry Andric   C.addTransition(State, Node, PreviousCallNote);
231349cc55cSDimitry Andric }
232349cc55cSDimitry Andric 
233349cc55cSDimitry Andric // TODO: This seems really ugly. Simplify this.
234349cc55cSDimitry Andric static const MemRegion *findInvalidatedSymbolicBase(ProgramStateRef State,
235349cc55cSDimitry Andric                                                     const MemRegion *Reg) {
236349cc55cSDimitry Andric   while (Reg) {
237349cc55cSDimitry Andric     if (State->contains<InvalidMemoryRegions>(Reg))
238349cc55cSDimitry Andric       return Reg;
239349cc55cSDimitry Andric     const auto *SymBase = Reg->getSymbolicBase();
240349cc55cSDimitry Andric     if (!SymBase)
241349cc55cSDimitry Andric       break;
242349cc55cSDimitry Andric     const auto *SRV = dyn_cast<SymbolRegionValue>(SymBase->getSymbol());
243349cc55cSDimitry Andric     if (!SRV)
244349cc55cSDimitry Andric       break;
245349cc55cSDimitry Andric     Reg = SRV->getRegion();
246349cc55cSDimitry Andric     if (const auto *VarReg = dyn_cast<VarRegion>(SRV->getRegion()))
247349cc55cSDimitry Andric       Reg = VarReg;
248349cc55cSDimitry Andric   }
249349cc55cSDimitry Andric   return nullptr;
250349cc55cSDimitry Andric }
251349cc55cSDimitry Andric 
252349cc55cSDimitry Andric // Handle functions in EnvpInvalidatingFunctions, that invalidate environment
253349cc55cSDimitry Andric // pointer from 'main()' Also, check if invalidated region is passed to a
254349cc55cSDimitry Andric // function call as an argument.
255349cc55cSDimitry Andric void InvalidPtrChecker::checkPostCall(const CallEvent &Call,
256349cc55cSDimitry Andric                                       CheckerContext &C) const {
2575f757f3fSDimitry Andric 
2585f757f3fSDimitry Andric   ProgramStateRef State = C.getState();
2595f757f3fSDimitry Andric 
2605f757f3fSDimitry Andric   // Model 'getenv' calls
2615f757f3fSDimitry Andric   if (GetEnvCall.matches(Call)) {
2625f757f3fSDimitry Andric     const MemRegion *Region = Call.getReturnValue().getAsRegion();
2635f757f3fSDimitry Andric     if (Region) {
2645f757f3fSDimitry Andric       State = State->add<GetenvEnvPtrRegions>(Region);
2655f757f3fSDimitry Andric       C.addTransition(State);
2665f757f3fSDimitry Andric     }
2675f757f3fSDimitry Andric   }
2685f757f3fSDimitry Andric 
269349cc55cSDimitry Andric   // Check if function invalidates 'envp' argument of 'main'
270349cc55cSDimitry Andric   if (const auto *Handler = EnvpInvalidatingFunctions.lookup(Call))
271349cc55cSDimitry Andric     (this->**Handler)(Call, C);
272349cc55cSDimitry Andric 
273349cc55cSDimitry Andric   // Check if function invalidates the result of previous call
274349cc55cSDimitry Andric   if (const auto *Handler = PreviousCallInvalidatingFunctions.lookup(Call))
275349cc55cSDimitry Andric     (this->**Handler)(Call, C);
276349cc55cSDimitry Andric 
2775f757f3fSDimitry Andric   // If pedantic mode is on, regard 'getenv' calls invalidating as well
2785f757f3fSDimitry Andric   if (InvalidatingGetEnv && GetEnvCall.matches(Call))
2795f757f3fSDimitry Andric     postPreviousReturnInvalidatingCall(Call, C);
2805f757f3fSDimitry Andric 
281349cc55cSDimitry Andric   // Check if one of the arguments of the function call is invalidated
282349cc55cSDimitry Andric 
283349cc55cSDimitry Andric   // If call was inlined, don't report invalidated argument
284349cc55cSDimitry Andric   if (C.wasInlined)
285349cc55cSDimitry Andric     return;
286349cc55cSDimitry Andric 
287349cc55cSDimitry Andric   for (unsigned I = 0, NumArgs = Call.getNumArgs(); I < NumArgs; ++I) {
288349cc55cSDimitry Andric 
289349cc55cSDimitry Andric     if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(
290349cc55cSDimitry Andric             Call.getArgSVal(I).getAsRegion())) {
291349cc55cSDimitry Andric       if (const MemRegion *InvalidatedSymbolicBase =
292349cc55cSDimitry Andric               findInvalidatedSymbolicBase(State, SR)) {
293349cc55cSDimitry Andric         ExplodedNode *ErrorNode = C.generateNonFatalErrorNode();
294349cc55cSDimitry Andric         if (!ErrorNode)
295349cc55cSDimitry Andric           return;
296349cc55cSDimitry Andric 
297349cc55cSDimitry Andric         SmallString<256> Msg;
298349cc55cSDimitry Andric         llvm::raw_svector_ostream Out(Msg);
299349cc55cSDimitry Andric         Out << "use of invalidated pointer '";
300349cc55cSDimitry Andric         Call.getArgExpr(I)->printPretty(Out, /*Helper=*/nullptr,
301349cc55cSDimitry Andric                                         C.getASTContext().getPrintingPolicy());
302349cc55cSDimitry Andric         Out << "' in a function call";
303349cc55cSDimitry Andric 
3045f757f3fSDimitry Andric         auto Report = std::make_unique<PathSensitiveBugReport>(
3055f757f3fSDimitry Andric             InvalidPtrBugType, Out.str(), ErrorNode);
306349cc55cSDimitry Andric         Report->markInteresting(InvalidatedSymbolicBase);
307349cc55cSDimitry Andric         Report->addRange(Call.getArgSourceRange(I));
308349cc55cSDimitry Andric         C.emitReport(std::move(Report));
309349cc55cSDimitry Andric       }
310349cc55cSDimitry Andric     }
311349cc55cSDimitry Andric   }
312349cc55cSDimitry Andric }
313349cc55cSDimitry Andric 
314349cc55cSDimitry Andric // Obtain the environment pointer from 'main()', if present.
315349cc55cSDimitry Andric void InvalidPtrChecker::checkBeginFunction(CheckerContext &C) const {
316349cc55cSDimitry Andric   if (!C.inTopFrame())
317349cc55cSDimitry Andric     return;
318349cc55cSDimitry Andric 
319349cc55cSDimitry Andric   const auto *FD = dyn_cast<FunctionDecl>(C.getLocationContext()->getDecl());
320349cc55cSDimitry Andric   if (!FD || FD->param_size() != 3 || !FD->isMain())
321349cc55cSDimitry Andric     return;
322349cc55cSDimitry Andric 
323349cc55cSDimitry Andric   ProgramStateRef State = C.getState();
324349cc55cSDimitry Andric   const MemRegion *EnvpReg =
325349cc55cSDimitry Andric       State->getRegion(FD->parameters()[2], C.getLocationContext());
326349cc55cSDimitry Andric 
327349cc55cSDimitry Andric   // Save the memory region pointed by the environment pointer parameter of
328349cc55cSDimitry Andric   // 'main'.
3295f757f3fSDimitry Andric   C.addTransition(State->set<MainEnvPtrRegion>(EnvpReg));
330349cc55cSDimitry Andric }
331349cc55cSDimitry Andric 
332349cc55cSDimitry Andric // Check if invalidated region is being dereferenced.
333349cc55cSDimitry Andric void InvalidPtrChecker::checkLocation(SVal Loc, bool isLoad, const Stmt *S,
334349cc55cSDimitry Andric                                       CheckerContext &C) const {
335349cc55cSDimitry Andric   ProgramStateRef State = C.getState();
336349cc55cSDimitry Andric 
337349cc55cSDimitry Andric   // Ignore memory operations involving 'non-invalidated' locations.
338349cc55cSDimitry Andric   const MemRegion *InvalidatedSymbolicBase =
339349cc55cSDimitry Andric       findInvalidatedSymbolicBase(State, Loc.getAsRegion());
340349cc55cSDimitry Andric   if (!InvalidatedSymbolicBase)
341349cc55cSDimitry Andric     return;
342349cc55cSDimitry Andric 
343349cc55cSDimitry Andric   ExplodedNode *ErrorNode = C.generateNonFatalErrorNode();
344349cc55cSDimitry Andric   if (!ErrorNode)
345349cc55cSDimitry Andric     return;
346349cc55cSDimitry Andric 
347349cc55cSDimitry Andric   auto Report = std::make_unique<PathSensitiveBugReport>(
3485f757f3fSDimitry Andric       InvalidPtrBugType, "dereferencing an invalid pointer", ErrorNode);
349349cc55cSDimitry Andric   Report->markInteresting(InvalidatedSymbolicBase);
350349cc55cSDimitry Andric   C.emitReport(std::move(Report));
351349cc55cSDimitry Andric }
352349cc55cSDimitry Andric 
353349cc55cSDimitry Andric void ento::registerInvalidPtrChecker(CheckerManager &Mgr) {
3545f757f3fSDimitry Andric   auto *Checker = Mgr.registerChecker<InvalidPtrChecker>();
3555f757f3fSDimitry Andric   Checker->InvalidatingGetEnv =
3565f757f3fSDimitry Andric       Mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker,
3575f757f3fSDimitry Andric                                                        "InvalidatingGetEnv");
358349cc55cSDimitry Andric }
359349cc55cSDimitry Andric 
360349cc55cSDimitry Andric bool ento::shouldRegisterInvalidPtrChecker(const CheckerManager &) {
361349cc55cSDimitry Andric   return true;
362349cc55cSDimitry Andric }
363