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 {{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,
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},
97 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
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(
190 if (
const MemRegion *
const *Reg = State->get<PreviousCallResultMap>(FD)) {
192 State = State->add<InvalidMemoryRegions>(PrevReg);
194 llvm::raw_ostream &Out) {
199 Out <<
"' call may invalidate the result of the previous " <<
'\'';
206 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
210 CE, LCtx, CE->getType(),
C.blockCount());
211 State = State->BindExpr(CE, LCtx, RetVal);
213 const auto *SymRegOfRetVal =
214 dyn_cast_or_null<SymbolicRegion>(RetVal.
getAsRegion());
220 State = State->set<PreviousCallResultMap>(FD, MR);
223 const NoteTag *PreviousCallNote =
C.getNoteTag(
227 Out <<
"previous function call was here";
230 C.addTransition(State,
Node, PreviousCallNote);
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()))
261 if (GetEnvCall.matches(
Call)) {
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)) {
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);
307 Report->addRange(
Call.getArgSourceRange(I));
308 C.emitReport(std::move(Report));
319 const auto *FD = dyn_cast<FunctionDecl>(
C.getLocationContext()->getDecl());
320 if (!FD || FD->param_size() != 3 || !FD->isMain())
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,
338 const MemRegion *InvalidatedSymbolicBase =
340 if (!InvalidatedSymbolicBase)
347 auto Report = std::make_unique<PathSensitiveBugReport>(
348 InvalidPtrBugType,
"dereferencing an invalid pointer", ErrorNode);
349 Report->markInteresting(InvalidatedSymbolicBase);
350 C.emitReport(std::move(Report));
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
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.