30class InvalidPtrChecker
31 :
public Checker<check::Location, check::BeginFunction, check::PostCall> {
35 BugType InvalidPtrBugType{
this,
"Use of invalidated pointer",
38 void EnvpInvalidatingCall(
const CallEvent &
Call, CheckerContext &
C)
const;
40 using HandlerFn = void (InvalidPtrChecker::*)(
const CallEvent &
Call,
41 CheckerContext &
C)
const;
48 bool InvalidatingGetEnv =
false;
51 const CallDescription GetEnvCall{CDM::CLibrary, {
"getenv"}, 1};
53 const CallDescriptionMap<HandlerFn> EnvpInvalidatingFunctions = {
54 {{CDM::CLibrary, {
"setenv"}, 3},
55 &InvalidPtrChecker::EnvpInvalidatingCall},
56 {{CDM::CLibrary, {
"unsetenv"}, 1},
57 &InvalidPtrChecker::EnvpInvalidatingCall},
58 {{CDM::CLibrary, {
"putenv"}, 1},
59 &InvalidPtrChecker::EnvpInvalidatingCall},
60 {{CDM::CLibrary, {
"_putenv_s"}, 2},
61 &InvalidPtrChecker::EnvpInvalidatingCall},
62 {{CDM::CLibrary, {
"_wputenv_s"}, 2},
63 &InvalidPtrChecker::EnvpInvalidatingCall},
66 void postPreviousReturnInvalidatingCall(
const CallEvent &
Call,
67 CheckerContext &
C)
const;
70 const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions = {
71 {{CDM::CLibrary, {
"setlocale"}, 2},
72 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
73 {{CDM::CLibrary, {
"strerror"}, 1},
74 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
75 {{CDM::CLibrary, {
"localeconv"}, 0},
76 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
77 {{CDM::CLibrary, {
"asctime"}, 1},
78 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
83 friend void ento::registerInvalidPtrChecker(CheckerManager &);
87 void checkBeginFunction(CheckerContext &
C)
const;
94 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
97 void checkLocation(SVal l,
bool isLoad,
const Stmt *S,
98 CheckerContext &
C)
const;
101 const NoteTag *createEnvInvalidationNote(CheckerContext &
C,
103 StringRef FunctionName)
const;
122const
NoteTag *InvalidPtrChecker::createEnvInvalidationNote(
125 const MemRegion *MainRegion = State->get<MainEnvPtrRegion>();
126 const auto GetenvRegions = State->get<GetenvEnvPtrRegions>();
128 return C.getNoteTag([
this, MainRegion, GetenvRegions,
129 FunctionName = std::string{FunctionName}](
132 if (&BR.getBugType() != &InvalidPtrBugType)
140 if (BR.isInteresting(MainRegion)) {
141 BR.markNotInteresting(MainRegion);
142 InvalidLocationNames.push_back(
"the environment parameter of 'main'");
144 bool InterestingGetenvFound =
false;
145 for (
const MemRegion *MR : GetenvRegions) {
146 if (BR.isInteresting(MR)) {
147 BR.markNotInteresting(MR);
148 if (!InterestingGetenvFound) {
149 InterestingGetenvFound =
true;
150 InvalidLocationNames.push_back(
151 "the environment returned by 'getenv'");
157 if (InvalidLocationNames.size() >= 1)
158 Out <<
'\'' << FunctionName <<
"' call may invalidate "
159 << InvalidLocationNames[0];
160 if (InvalidLocationNames.size() == 2)
161 Out <<
", and " << InvalidLocationNames[1];
165void InvalidPtrChecker::EnvpInvalidatingCall(
const CallEvent &
Call,
170 if (
const MemRegion *MainEnvPtr = State->get<MainEnvPtrRegion>())
171 State = State->add<InvalidMemoryRegions>(MainEnvPtr);
172 for (
const MemRegion *EnvPtr : State->get<GetenvEnvPtrRegions>())
173 State = State->add<InvalidMemoryRegions>(EnvPtr);
175 StringRef FunctionName =
Call.getCalleeIdentifier()->getName();
176 const NoteTag *InvalidationNote =
177 createEnvInvalidationNote(
C, State, FunctionName);
179 C.addTransition(State, InvalidationNote);
182void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
183 const CallEvent &
Call, CheckerContext &
C)
const {
186 const NoteTag *
Note =
nullptr;
187 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
190 if (
const MemRegion *
const *Reg = State->get<PreviousCallResultMap>(FD)) {
191 const MemRegion *PrevReg = *Reg;
192 State = State->add<InvalidMemoryRegions>(PrevReg);
193 Note =
C.getNoteTag([
this, PrevReg, FD](PathSensitiveBugReport &BR,
194 llvm::raw_ostream &Out) {
199 Out <<
"' call may invalidate the result of the previous " <<
'\'';
205 const LocationContext *LCtx =
C.getLocationContext();
209 DefinedOrUnknownSVal RetVal =
210 C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
211 State = State->BindExpr(CE, LCtx, RetVal);
213 const auto *SymRegOfRetVal =
214 dyn_cast_or_null<SymbolicRegion>(RetVal.
getAsRegion());
219 const MemRegion *MR = SymRegOfRetVal->getBaseRegion();
220 State = State->set<PreviousCallResultMap>(FD, MR);
222 ExplodedNode *Node =
C.addTransition(State,
Note);
223 const NoteTag *PreviousCallNote =
C.getNoteTag(
224 [
this, MR](PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
227 Out <<
"previous function call was here";
230 C.addTransition(State, Node, PreviousCallNote);
234static const MemRegion *findInvalidatedSymbolicBase(
ProgramStateRef State,
235 const MemRegion *Reg) {
237 if (State->contains<InvalidMemoryRegions>(Reg))
242 const auto *SRV = dyn_cast<SymbolRegionValue>(SymBase->getSymbol());
245 Reg = SRV->getRegion();
246 if (
const auto *VarReg = dyn_cast<VarRegion>(SRV->getRegion()))
255void InvalidPtrChecker::checkPostCall(
const CallEvent &
Call,
256 CheckerContext &
C)
const {
262 const MemRegion *Region =
Call.getReturnValue().getAsRegion();
264 State = State->add<GetenvEnvPtrRegions>(Region);
265 C.addTransition(State);
270 if (
const auto *Handler = EnvpInvalidatingFunctions.lookup(
Call))
271 (this->**Handler)(
Call,
C);
274 if (
const auto *Handler = PreviousCallInvalidatingFunctions.lookup(
Call))
275 (this->**Handler)(
Call,
C);
278 if (InvalidatingGetEnv && GetEnvCall.
matches(
Call))
279 postPreviousReturnInvalidatingCall(
Call,
C);
287 for (
unsigned I = 0, NumArgs =
Call.getNumArgs(); I < NumArgs; ++I) {
289 if (
const auto *SR = dyn_cast_or_null<SymbolicRegion>(
290 Call.getArgSVal(I).getAsRegion())) {
291 if (
const MemRegion *InvalidatedSymbolicBase =
292 findInvalidatedSymbolicBase(State, SR)) {
293 ExplodedNode *ErrorNode =
C.generateNonFatalErrorNode();
297 SmallString<256> Msg;
298 llvm::raw_svector_ostream
Out(Msg);
299 Out <<
"use of invalidated pointer '";
300 Call.getArgExpr(I)->printPretty(Out,
nullptr,
301 C.getASTContext().getPrintingPolicy());
302 Out <<
"' in a function call";
304 auto Report = std::make_unique<PathSensitiveBugReport>(
305 InvalidPtrBugType,
Out.str(), ErrorNode);
306 Report->markInteresting(InvalidatedSymbolicBase);
308 C.emitReport(std::move(
Report));
315void InvalidPtrChecker::checkBeginFunction(CheckerContext &
C)
const {
319 const auto *FD = dyn_cast<FunctionDecl>(
C.getLocationContext()->getDecl());
320 if (!FD || FD->param_size() != 3 || !FD->isMain())
324 const MemRegion *EnvpReg =
325 State->getRegion(FD->parameters()[2],
C.getLocationContext());
329 C.addTransition(State->set<MainEnvPtrRegion>(EnvpReg));
333void InvalidPtrChecker::checkLocation(SVal Loc,
bool isLoad,
const Stmt *S,
334 CheckerContext &
C)
const {
338 const MemRegion *InvalidatedSymbolicBase =
339 findInvalidatedSymbolicBase(State, Loc.
getAsRegion());
340 if (!InvalidatedSymbolicBase)
343 ExplodedNode *ErrorNode =
C.generateNonFatalErrorNode();
347 auto Report = std::make_unique<PathSensitiveBugReport>(
348 InvalidPtrBugType,
"dereferencing an invalid pointer", ErrorNode);
349 Report->markInteresting(InvalidatedSymbolicBase);
350 C.emitReport(std::move(
Report));
353void ento::registerInvalidPtrChecker(CheckerManager &Mgr) {
355 Checker->InvalidatingGetEnv =
357 "InvalidatingGetEnv");
360bool ento::shouldRegisterInvalidPtrChecker(
const CheckerManager &) {
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
const LangOptions & getLangOpts() const
ASTContext & getASTContext() const LLVM_READONLY
Represents a function declaration or definition.
void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const override
Appends a human-readable name for this declaration into the given stream.
const BugType & getBugType() const
bool matches(const CallEvent &Call) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
Represents an abstract call to a function or method along a particular path.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
MemRegion - The root abstract class for all memory regions.
const SymbolicRegion * getSymbolicBase() const
If this is a symbolic region, returns the region.
The tag upon which the TagVisitor reacts.
bool isInteresting(SymbolRef sym) const
const MemRegion * getAsRegion() const
const char *const MemoryError
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
The JSON file list parser is used to communicate input to InstallAPI.
U cast(CodeGen::Address addr)