30class InvalidPtrChecker
31 :
public Checker<check::Location, check::BeginFunction, check::PostCall> {
35 BugType InvalidPtrBugType{
this,
"Use of invalidated pointer",
40 using HandlerFn = void (InvalidPtrChecker::*)(
const CallEvent &
Call,
48 bool InvalidatingGetEnv =
false;
54 {{{
"setenv"}, 3}, &InvalidPtrChecker::EnvpInvalidatingCall},
55 {{{
"unsetenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
56 {{{
"putenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
57 {{{
"_putenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
58 {{{
"_wputenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
61 void postPreviousReturnInvalidatingCall(
const CallEvent &
Call,
67 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
69 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
71 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
73 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
92 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
98 StringRef FunctionName)
const;
117const
NoteTag *InvalidPtrChecker::createEnvInvalidationNote(
120 const MemRegion *MainRegion = State->get<MainEnvPtrRegion>();
121 const auto GetenvRegions = State->get<GetenvEnvPtrRegions>();
123 return C.getNoteTag([
this, MainRegion, GetenvRegions,
124 FunctionName = std::string{FunctionName}](
127 if (&BR.getBugType() != &InvalidPtrBugType)
135 if (BR.isInteresting(MainRegion)) {
136 BR.markNotInteresting(MainRegion);
137 InvalidLocationNames.push_back(
"the environment parameter of 'main'");
139 bool InterestingGetenvFound =
false;
140 for (
const MemRegion *MR : GetenvRegions) {
141 if (BR.isInteresting(MR)) {
142 BR.markNotInteresting(MR);
143 if (!InterestingGetenvFound) {
144 InterestingGetenvFound =
true;
145 InvalidLocationNames.push_back(
146 "the environment returned by 'getenv'");
152 if (InvalidLocationNames.size() >= 1)
153 Out <<
'\'' << FunctionName <<
"' call may invalidate "
154 << InvalidLocationNames[0];
155 if (InvalidLocationNames.size() == 2)
156 Out <<
", and " << InvalidLocationNames[1];
160void InvalidPtrChecker::EnvpInvalidatingCall(
const CallEvent &
Call,
165 if (
const MemRegion *MainEnvPtr = State->get<MainEnvPtrRegion>())
166 State = State->add<InvalidMemoryRegions>(MainEnvPtr);
167 for (
const MemRegion *EnvPtr : State->get<GetenvEnvPtrRegions>())
168 State = State->add<InvalidMemoryRegions>(EnvPtr);
170 StringRef FunctionName =
Call.getCalleeIdentifier()->getName();
171 const NoteTag *InvalidationNote =
172 createEnvInvalidationNote(
C, State, FunctionName);
174 C.addTransition(State, InvalidationNote);
177void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
185 if (
const MemRegion *
const *Reg = State->get<PreviousCallResultMap>(FD)) {
187 State = State->add<InvalidMemoryRegions>(PrevReg);
189 llvm::raw_ostream &Out) {
194 Out <<
"' call may invalidate the result of the previous " <<
'\'';
201 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
205 CE, LCtx, CE->getType(),
C.blockCount());
206 State = State->BindExpr(CE, LCtx, RetVal);
209 const auto *SymRegOfRetVal = cast<SymbolicRegion>(RetVal.
getAsRegion());
211 State = State->set<PreviousCallResultMap>(FD, MR);
214 const NoteTag *PreviousCallNote =
C.getNoteTag(
218 Out <<
"previous function call was here";
221 C.addTransition(State,
Node, PreviousCallNote);
228 if (State->contains<InvalidMemoryRegions>(Reg))
233 const auto *SRV = dyn_cast<SymbolRegionValue>(SymBase->getSymbol());
236 Reg = SRV->getRegion();
237 if (
const auto *VarReg = dyn_cast<VarRegion>(SRV->getRegion()))
252 if (GetEnvCall.matches(
Call)) {
253 const MemRegion *Region =
Call.getReturnValue().getAsRegion();
255 State = State->add<GetenvEnvPtrRegions>(Region);
256 C.addTransition(State);
261 if (
const auto *Handler = EnvpInvalidatingFunctions.lookup(
Call))
262 (this->**Handler)(
Call,
C);
265 if (
const auto *Handler = PreviousCallInvalidatingFunctions.lookup(
Call))
266 (this->**Handler)(
Call,
C);
269 if (InvalidatingGetEnv && GetEnvCall.matches(
Call))
270 postPreviousReturnInvalidatingCall(
Call,
C);
278 for (
unsigned I = 0, NumArgs =
Call.getNumArgs(); I < NumArgs; ++I) {
280 if (
const auto *SR = dyn_cast_or_null<SymbolicRegion>(
281 Call.getArgSVal(I).getAsRegion())) {
282 if (
const MemRegion *InvalidatedSymbolicBase =
283 findInvalidatedSymbolicBase(State, SR)) {
289 llvm::raw_svector_ostream Out(Msg);
290 Out <<
"use of invalidated pointer '";
291 Call.getArgExpr(I)->printPretty(Out,
nullptr,
292 C.getASTContext().getPrintingPolicy());
293 Out <<
"' in a function call";
295 auto Report = std::make_unique<PathSensitiveBugReport>(
296 InvalidPtrBugType, Out.str(), ErrorNode);
297 Report->markInteresting(InvalidatedSymbolicBase);
298 Report->addRange(
Call.getArgSourceRange(I));
299 C.emitReport(std::move(Report));
310 const auto *FD = dyn_cast<FunctionDecl>(
C.getLocationContext()->getDecl());
311 if (!FD || FD->param_size() != 3 || !FD->isMain())
316 State->getRegion(FD->parameters()[2],
C.getLocationContext());
320 C.addTransition(State->set<MainEnvPtrRegion>(EnvpReg));
324void InvalidPtrChecker::checkLocation(
SVal Loc,
bool isLoad,
const Stmt *S,
329 const MemRegion *InvalidatedSymbolicBase =
331 if (!InvalidatedSymbolicBase)
338 auto Report = std::make_unique<PathSensitiveBugReport>(
339 InvalidPtrBugType,
"dereferencing an invalid pointer", ErrorNode);
340 Report->markInteresting(InvalidatedSymbolicBase);
341 C.emitReport(std::move(Report));
348 "InvalidatingGetEnv");
351bool 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
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
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.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
Stmt - This represents one statement.
const BugType & getBugType() const
An immutable map from CallDescriptions to arbitrary data.
A CallDescription is a pattern that can be used to match calls based on the qualified name and the ar...
Represents an abstract call to a function or method along a particular path.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
MemRegion - The root abstract class for all memory regions.
const SymbolicRegion * getSymbolicBase() const
If this is a symbolic region, returns the region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
The tag upon which the TagVisitor reacts.
bool isInteresting(SymbolRef sym) const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
const MemRegion * getAsRegion() const
const char *const MemoryError
The JSON file list parser is used to communicate input to InstallAPI.