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