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: 33*5f757f3fSDimitry Andric // For accurate emission of NoteTags, the BugType of this checker should have 34*5f757f3fSDimitry Andric // a unique address. 35*5f757f3fSDimitry Andric BugType InvalidPtrBugType{this, "Use of invalidated pointer", 36*5f757f3fSDimitry 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 44*5f757f3fSDimitry Andric 45*5f757f3fSDimitry Andric // If set to true, consider getenv calls as invalidating operations on the 46*5f757f3fSDimitry Andric // environment variable buffer. This is implied in the standard, but in 47*5f757f3fSDimitry Andric // practice does not cause problems (in the commonly used environments). 48*5f757f3fSDimitry Andric bool InvalidatingGetEnv = false; 49*5f757f3fSDimitry Andric 50*5f757f3fSDimitry Andric // GetEnv can be treated invalidating and non-invalidating as well. 51*5f757f3fSDimitry Andric const CallDescription GetEnvCall{{"getenv"}, 1}; 52*5f757f3fSDimitry Andric 53349cc55cSDimitry Andric const CallDescriptionMap<HandlerFn> EnvpInvalidatingFunctions = { 54bdd1243dSDimitry Andric {{{"setenv"}, 3}, &InvalidPtrChecker::EnvpInvalidatingCall}, 55bdd1243dSDimitry Andric {{{"unsetenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall}, 56bdd1243dSDimitry Andric {{{"putenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall}, 57bdd1243dSDimitry Andric {{{"_putenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall}, 58bdd1243dSDimitry Andric {{{"_wputenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall}, 59349cc55cSDimitry Andric }; 60349cc55cSDimitry Andric 61349cc55cSDimitry Andric void postPreviousReturnInvalidatingCall(const CallEvent &Call, 62349cc55cSDimitry Andric CheckerContext &C) const; 63349cc55cSDimitry Andric 64349cc55cSDimitry Andric // SEI CERT ENV34-C 65349cc55cSDimitry Andric const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions = { 66bdd1243dSDimitry Andric {{{"setlocale"}, 2}, 67349cc55cSDimitry Andric &InvalidPtrChecker::postPreviousReturnInvalidatingCall}, 68bdd1243dSDimitry Andric {{{"strerror"}, 1}, 69349cc55cSDimitry Andric &InvalidPtrChecker::postPreviousReturnInvalidatingCall}, 70bdd1243dSDimitry Andric {{{"localeconv"}, 0}, 71bdd1243dSDimitry Andric &InvalidPtrChecker::postPreviousReturnInvalidatingCall}, 72bdd1243dSDimitry Andric {{{"asctime"}, 1}, 73bdd1243dSDimitry Andric &InvalidPtrChecker::postPreviousReturnInvalidatingCall}, 74349cc55cSDimitry Andric }; 75349cc55cSDimitry Andric 76*5f757f3fSDimitry Andric // The private members of this checker corresponding to commandline options 77*5f757f3fSDimitry Andric // are set in this function. 78*5f757f3fSDimitry Andric friend void ento::registerInvalidPtrChecker(CheckerManager &); 79*5f757f3fSDimitry Andric 80349cc55cSDimitry Andric public: 81349cc55cSDimitry Andric // Obtain the environment pointer from 'main()' (if present). 82349cc55cSDimitry Andric void checkBeginFunction(CheckerContext &C) const; 83349cc55cSDimitry Andric 84349cc55cSDimitry Andric // Handle functions in EnvpInvalidatingFunctions, that invalidate environment 85349cc55cSDimitry Andric // pointer from 'main()' 86349cc55cSDimitry Andric // Handle functions in PreviousCallInvalidatingFunctions. 87349cc55cSDimitry Andric // Also, check if invalidated region is passed to a 88349cc55cSDimitry Andric // conservatively evaluated function call as an argument. 89349cc55cSDimitry Andric void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 90349cc55cSDimitry Andric 91349cc55cSDimitry Andric // Check if invalidated region is being dereferenced. 92349cc55cSDimitry Andric void checkLocation(SVal l, bool isLoad, const Stmt *S, 93349cc55cSDimitry Andric CheckerContext &C) const; 94*5f757f3fSDimitry Andric 95*5f757f3fSDimitry Andric private: 96*5f757f3fSDimitry Andric const NoteTag *createEnvInvalidationNote(CheckerContext &C, 97*5f757f3fSDimitry Andric ProgramStateRef State, 98*5f757f3fSDimitry Andric StringRef FunctionName) const; 99349cc55cSDimitry Andric }; 100349cc55cSDimitry Andric 101349cc55cSDimitry Andric } // namespace 102349cc55cSDimitry Andric 103349cc55cSDimitry Andric // Set of memory regions that were invalidated 104349cc55cSDimitry Andric REGISTER_SET_WITH_PROGRAMSTATE(InvalidMemoryRegions, const MemRegion *) 105349cc55cSDimitry Andric 106349cc55cSDimitry Andric // Stores the region of the environment pointer of 'main' (if present). 107*5f757f3fSDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(MainEnvPtrRegion, const MemRegion *) 108*5f757f3fSDimitry Andric 109*5f757f3fSDimitry Andric // Stores the regions of environments returned by getenv calls. 110*5f757f3fSDimitry Andric REGISTER_SET_WITH_PROGRAMSTATE(GetenvEnvPtrRegions, const MemRegion *) 111349cc55cSDimitry Andric 112349cc55cSDimitry Andric // Stores key-value pairs, where key is function declaration and value is 113349cc55cSDimitry Andric // pointer to memory region returned by previous call of this function 114349cc55cSDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(PreviousCallResultMap, const FunctionDecl *, 115349cc55cSDimitry Andric const MemRegion *) 116349cc55cSDimitry Andric 117*5f757f3fSDimitry Andric const NoteTag *InvalidPtrChecker::createEnvInvalidationNote( 118*5f757f3fSDimitry Andric CheckerContext &C, ProgramStateRef State, StringRef FunctionName) const { 119*5f757f3fSDimitry Andric 120*5f757f3fSDimitry Andric const MemRegion *MainRegion = State->get<MainEnvPtrRegion>(); 121*5f757f3fSDimitry Andric const auto GetenvRegions = State->get<GetenvEnvPtrRegions>(); 122*5f757f3fSDimitry Andric 123*5f757f3fSDimitry Andric return C.getNoteTag([this, MainRegion, GetenvRegions, 124*5f757f3fSDimitry Andric FunctionName = std::string{FunctionName}]( 125*5f757f3fSDimitry Andric PathSensitiveBugReport &BR, llvm::raw_ostream &Out) { 126*5f757f3fSDimitry Andric // Only handle the BugType of this checker. 127*5f757f3fSDimitry Andric if (&BR.getBugType() != &InvalidPtrBugType) 128*5f757f3fSDimitry Andric return; 129*5f757f3fSDimitry Andric 130*5f757f3fSDimitry Andric // Mark all regions that were interesting before as NOT interesting now 131*5f757f3fSDimitry Andric // to avoid extra notes coming from invalidation points higher up the 132*5f757f3fSDimitry Andric // bugpath. This ensures that only the last invalidation point is marked 133*5f757f3fSDimitry Andric // with a note tag. 134*5f757f3fSDimitry Andric llvm::SmallVector<std::string, 2> InvalidLocationNames; 135*5f757f3fSDimitry Andric if (BR.isInteresting(MainRegion)) { 136*5f757f3fSDimitry Andric BR.markNotInteresting(MainRegion); 137*5f757f3fSDimitry Andric InvalidLocationNames.push_back("the environment parameter of 'main'"); 138*5f757f3fSDimitry Andric } 139*5f757f3fSDimitry Andric bool InterestingGetenvFound = false; 140*5f757f3fSDimitry Andric for (const MemRegion *MR : GetenvRegions) { 141*5f757f3fSDimitry Andric if (BR.isInteresting(MR)) { 142*5f757f3fSDimitry Andric BR.markNotInteresting(MR); 143*5f757f3fSDimitry Andric if (!InterestingGetenvFound) { 144*5f757f3fSDimitry Andric InterestingGetenvFound = true; 145*5f757f3fSDimitry Andric InvalidLocationNames.push_back( 146*5f757f3fSDimitry Andric "the environment returned by 'getenv'"); 147*5f757f3fSDimitry Andric } 148*5f757f3fSDimitry Andric } 149*5f757f3fSDimitry Andric } 150*5f757f3fSDimitry Andric 151*5f757f3fSDimitry Andric // Emit note tag message. 152*5f757f3fSDimitry Andric if (InvalidLocationNames.size() >= 1) 153*5f757f3fSDimitry Andric Out << '\'' << FunctionName << "' call may invalidate " 154*5f757f3fSDimitry Andric << InvalidLocationNames[0]; 155*5f757f3fSDimitry Andric if (InvalidLocationNames.size() == 2) 156*5f757f3fSDimitry Andric Out << ", and " << InvalidLocationNames[1]; 157*5f757f3fSDimitry Andric }); 158*5f757f3fSDimitry Andric } 159*5f757f3fSDimitry Andric 160349cc55cSDimitry Andric void InvalidPtrChecker::EnvpInvalidatingCall(const CallEvent &Call, 161349cc55cSDimitry Andric CheckerContext &C) const { 162*5f757f3fSDimitry Andric // This callevent invalidates all previously generated pointers to the 163*5f757f3fSDimitry Andric // environment. 164349cc55cSDimitry Andric ProgramStateRef State = C.getState(); 165*5f757f3fSDimitry Andric if (const MemRegion *MainEnvPtr = State->get<MainEnvPtrRegion>()) 166*5f757f3fSDimitry Andric State = State->add<InvalidMemoryRegions>(MainEnvPtr); 167*5f757f3fSDimitry Andric for (const MemRegion *EnvPtr : State->get<GetenvEnvPtrRegions>()) 168*5f757f3fSDimitry Andric State = State->add<InvalidMemoryRegions>(EnvPtr); 169349cc55cSDimitry Andric 170*5f757f3fSDimitry Andric StringRef FunctionName = Call.getCalleeIdentifier()->getName(); 171*5f757f3fSDimitry Andric const NoteTag *InvalidationNote = 172*5f757f3fSDimitry Andric createEnvInvalidationNote(C, State, FunctionName); 173349cc55cSDimitry Andric 174*5f757f3fSDimitry Andric C.addTransition(State, InvalidationNote); 175349cc55cSDimitry Andric } 176349cc55cSDimitry Andric 177349cc55cSDimitry Andric void InvalidPtrChecker::postPreviousReturnInvalidatingCall( 178349cc55cSDimitry Andric const CallEvent &Call, CheckerContext &C) const { 179349cc55cSDimitry Andric ProgramStateRef State = C.getState(); 180349cc55cSDimitry Andric 181349cc55cSDimitry Andric const NoteTag *Note = nullptr; 182349cc55cSDimitry Andric const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 183349cc55cSDimitry Andric // Invalidate the region of the previously returned pointer - if there was 184349cc55cSDimitry Andric // one. 185349cc55cSDimitry Andric if (const MemRegion *const *Reg = State->get<PreviousCallResultMap>(FD)) { 186349cc55cSDimitry Andric const MemRegion *PrevReg = *Reg; 187349cc55cSDimitry Andric State = State->add<InvalidMemoryRegions>(PrevReg); 188*5f757f3fSDimitry Andric Note = C.getNoteTag([this, PrevReg, FD](PathSensitiveBugReport &BR, 189349cc55cSDimitry Andric llvm::raw_ostream &Out) { 190*5f757f3fSDimitry Andric if (!BR.isInteresting(PrevReg) || &BR.getBugType() != &InvalidPtrBugType) 191349cc55cSDimitry Andric return; 192349cc55cSDimitry Andric Out << '\''; 193349cc55cSDimitry Andric FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true); 19481ad6265SDimitry Andric Out << "' call may invalidate the result of the previous " << '\''; 195349cc55cSDimitry Andric FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true); 196349cc55cSDimitry Andric Out << '\''; 197349cc55cSDimitry Andric }); 198349cc55cSDimitry Andric } 199349cc55cSDimitry Andric 200349cc55cSDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 201349cc55cSDimitry Andric const auto *CE = cast<CallExpr>(Call.getOriginExpr()); 202349cc55cSDimitry Andric 203349cc55cSDimitry Andric // Function call will return a pointer to the new symbolic region. 204349cc55cSDimitry Andric DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal( 205349cc55cSDimitry Andric CE, LCtx, CE->getType(), C.blockCount()); 206349cc55cSDimitry Andric State = State->BindExpr(CE, LCtx, RetVal); 207349cc55cSDimitry Andric 208349cc55cSDimitry Andric // Remember to this region. 209349cc55cSDimitry Andric const auto *SymRegOfRetVal = cast<SymbolicRegion>(RetVal.getAsRegion()); 210*5f757f3fSDimitry Andric const MemRegion *MR = SymRegOfRetVal->getBaseRegion(); 211349cc55cSDimitry Andric State = State->set<PreviousCallResultMap>(FD, MR); 212349cc55cSDimitry Andric 213349cc55cSDimitry Andric ExplodedNode *Node = C.addTransition(State, Note); 214*5f757f3fSDimitry Andric const NoteTag *PreviousCallNote = C.getNoteTag( 215*5f757f3fSDimitry Andric [this, MR](PathSensitiveBugReport &BR, llvm::raw_ostream &Out) { 216*5f757f3fSDimitry Andric if (!BR.isInteresting(MR) || &BR.getBugType() != &InvalidPtrBugType) 217349cc55cSDimitry Andric return; 218*5f757f3fSDimitry Andric Out << "previous function call was here"; 219349cc55cSDimitry Andric }); 220349cc55cSDimitry Andric 221349cc55cSDimitry Andric C.addTransition(State, Node, PreviousCallNote); 222349cc55cSDimitry Andric } 223349cc55cSDimitry Andric 224349cc55cSDimitry Andric // TODO: This seems really ugly. Simplify this. 225349cc55cSDimitry Andric static const MemRegion *findInvalidatedSymbolicBase(ProgramStateRef State, 226349cc55cSDimitry Andric const MemRegion *Reg) { 227349cc55cSDimitry Andric while (Reg) { 228349cc55cSDimitry Andric if (State->contains<InvalidMemoryRegions>(Reg)) 229349cc55cSDimitry Andric return Reg; 230349cc55cSDimitry Andric const auto *SymBase = Reg->getSymbolicBase(); 231349cc55cSDimitry Andric if (!SymBase) 232349cc55cSDimitry Andric break; 233349cc55cSDimitry Andric const auto *SRV = dyn_cast<SymbolRegionValue>(SymBase->getSymbol()); 234349cc55cSDimitry Andric if (!SRV) 235349cc55cSDimitry Andric break; 236349cc55cSDimitry Andric Reg = SRV->getRegion(); 237349cc55cSDimitry Andric if (const auto *VarReg = dyn_cast<VarRegion>(SRV->getRegion())) 238349cc55cSDimitry Andric Reg = VarReg; 239349cc55cSDimitry Andric } 240349cc55cSDimitry Andric return nullptr; 241349cc55cSDimitry Andric } 242349cc55cSDimitry Andric 243349cc55cSDimitry Andric // Handle functions in EnvpInvalidatingFunctions, that invalidate environment 244349cc55cSDimitry Andric // pointer from 'main()' Also, check if invalidated region is passed to a 245349cc55cSDimitry Andric // function call as an argument. 246349cc55cSDimitry Andric void InvalidPtrChecker::checkPostCall(const CallEvent &Call, 247349cc55cSDimitry Andric CheckerContext &C) const { 248*5f757f3fSDimitry Andric 249*5f757f3fSDimitry Andric ProgramStateRef State = C.getState(); 250*5f757f3fSDimitry Andric 251*5f757f3fSDimitry Andric // Model 'getenv' calls 252*5f757f3fSDimitry Andric if (GetEnvCall.matches(Call)) { 253*5f757f3fSDimitry Andric const MemRegion *Region = Call.getReturnValue().getAsRegion(); 254*5f757f3fSDimitry Andric if (Region) { 255*5f757f3fSDimitry Andric State = State->add<GetenvEnvPtrRegions>(Region); 256*5f757f3fSDimitry Andric C.addTransition(State); 257*5f757f3fSDimitry Andric } 258*5f757f3fSDimitry Andric } 259*5f757f3fSDimitry Andric 260349cc55cSDimitry Andric // Check if function invalidates 'envp' argument of 'main' 261349cc55cSDimitry Andric if (const auto *Handler = EnvpInvalidatingFunctions.lookup(Call)) 262349cc55cSDimitry Andric (this->**Handler)(Call, C); 263349cc55cSDimitry Andric 264349cc55cSDimitry Andric // Check if function invalidates the result of previous call 265349cc55cSDimitry Andric if (const auto *Handler = PreviousCallInvalidatingFunctions.lookup(Call)) 266349cc55cSDimitry Andric (this->**Handler)(Call, C); 267349cc55cSDimitry Andric 268*5f757f3fSDimitry Andric // If pedantic mode is on, regard 'getenv' calls invalidating as well 269*5f757f3fSDimitry Andric if (InvalidatingGetEnv && GetEnvCall.matches(Call)) 270*5f757f3fSDimitry Andric postPreviousReturnInvalidatingCall(Call, C); 271*5f757f3fSDimitry Andric 272349cc55cSDimitry Andric // Check if one of the arguments of the function call is invalidated 273349cc55cSDimitry Andric 274349cc55cSDimitry Andric // If call was inlined, don't report invalidated argument 275349cc55cSDimitry Andric if (C.wasInlined) 276349cc55cSDimitry Andric return; 277349cc55cSDimitry Andric 278349cc55cSDimitry Andric for (unsigned I = 0, NumArgs = Call.getNumArgs(); I < NumArgs; ++I) { 279349cc55cSDimitry Andric 280349cc55cSDimitry Andric if (const auto *SR = dyn_cast_or_null<SymbolicRegion>( 281349cc55cSDimitry Andric Call.getArgSVal(I).getAsRegion())) { 282349cc55cSDimitry Andric if (const MemRegion *InvalidatedSymbolicBase = 283349cc55cSDimitry Andric findInvalidatedSymbolicBase(State, SR)) { 284349cc55cSDimitry Andric ExplodedNode *ErrorNode = C.generateNonFatalErrorNode(); 285349cc55cSDimitry Andric if (!ErrorNode) 286349cc55cSDimitry Andric return; 287349cc55cSDimitry Andric 288349cc55cSDimitry Andric SmallString<256> Msg; 289349cc55cSDimitry Andric llvm::raw_svector_ostream Out(Msg); 290349cc55cSDimitry Andric Out << "use of invalidated pointer '"; 291349cc55cSDimitry Andric Call.getArgExpr(I)->printPretty(Out, /*Helper=*/nullptr, 292349cc55cSDimitry Andric C.getASTContext().getPrintingPolicy()); 293349cc55cSDimitry Andric Out << "' in a function call"; 294349cc55cSDimitry Andric 295*5f757f3fSDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>( 296*5f757f3fSDimitry Andric InvalidPtrBugType, Out.str(), ErrorNode); 297349cc55cSDimitry Andric Report->markInteresting(InvalidatedSymbolicBase); 298349cc55cSDimitry Andric Report->addRange(Call.getArgSourceRange(I)); 299349cc55cSDimitry Andric C.emitReport(std::move(Report)); 300349cc55cSDimitry Andric } 301349cc55cSDimitry Andric } 302349cc55cSDimitry Andric } 303349cc55cSDimitry Andric } 304349cc55cSDimitry Andric 305349cc55cSDimitry Andric // Obtain the environment pointer from 'main()', if present. 306349cc55cSDimitry Andric void InvalidPtrChecker::checkBeginFunction(CheckerContext &C) const { 307349cc55cSDimitry Andric if (!C.inTopFrame()) 308349cc55cSDimitry Andric return; 309349cc55cSDimitry Andric 310349cc55cSDimitry Andric const auto *FD = dyn_cast<FunctionDecl>(C.getLocationContext()->getDecl()); 311349cc55cSDimitry Andric if (!FD || FD->param_size() != 3 || !FD->isMain()) 312349cc55cSDimitry Andric return; 313349cc55cSDimitry Andric 314349cc55cSDimitry Andric ProgramStateRef State = C.getState(); 315349cc55cSDimitry Andric const MemRegion *EnvpReg = 316349cc55cSDimitry Andric State->getRegion(FD->parameters()[2], C.getLocationContext()); 317349cc55cSDimitry Andric 318349cc55cSDimitry Andric // Save the memory region pointed by the environment pointer parameter of 319349cc55cSDimitry Andric // 'main'. 320*5f757f3fSDimitry Andric C.addTransition(State->set<MainEnvPtrRegion>(EnvpReg)); 321349cc55cSDimitry Andric } 322349cc55cSDimitry Andric 323349cc55cSDimitry Andric // Check if invalidated region is being dereferenced. 324349cc55cSDimitry Andric void InvalidPtrChecker::checkLocation(SVal Loc, bool isLoad, const Stmt *S, 325349cc55cSDimitry Andric CheckerContext &C) const { 326349cc55cSDimitry Andric ProgramStateRef State = C.getState(); 327349cc55cSDimitry Andric 328349cc55cSDimitry Andric // Ignore memory operations involving 'non-invalidated' locations. 329349cc55cSDimitry Andric const MemRegion *InvalidatedSymbolicBase = 330349cc55cSDimitry Andric findInvalidatedSymbolicBase(State, Loc.getAsRegion()); 331349cc55cSDimitry Andric if (!InvalidatedSymbolicBase) 332349cc55cSDimitry Andric return; 333349cc55cSDimitry Andric 334349cc55cSDimitry Andric ExplodedNode *ErrorNode = C.generateNonFatalErrorNode(); 335349cc55cSDimitry Andric if (!ErrorNode) 336349cc55cSDimitry Andric return; 337349cc55cSDimitry Andric 338349cc55cSDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>( 339*5f757f3fSDimitry Andric InvalidPtrBugType, "dereferencing an invalid pointer", ErrorNode); 340349cc55cSDimitry Andric Report->markInteresting(InvalidatedSymbolicBase); 341349cc55cSDimitry Andric C.emitReport(std::move(Report)); 342349cc55cSDimitry Andric } 343349cc55cSDimitry Andric 344349cc55cSDimitry Andric void ento::registerInvalidPtrChecker(CheckerManager &Mgr) { 345*5f757f3fSDimitry Andric auto *Checker = Mgr.registerChecker<InvalidPtrChecker>(); 346*5f757f3fSDimitry Andric Checker->InvalidatingGetEnv = 347*5f757f3fSDimitry Andric Mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, 348*5f757f3fSDimitry Andric "InvalidatingGetEnv"); 349349cc55cSDimitry Andric } 350349cc55cSDimitry Andric 351349cc55cSDimitry Andric bool ento::shouldRegisterInvalidPtrChecker(const CheckerManager &) { 352349cc55cSDimitry Andric return true; 353349cc55cSDimitry Andric } 354