25 using namespace clang;
30 class 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;
55 &InvalidPtrChecker::EnvpInvalidatingCall},
57 &InvalidPtrChecker::EnvpInvalidatingCall},
59 &InvalidPtrChecker::EnvpInvalidatingCall},
61 &InvalidPtrChecker::EnvpInvalidatingCall},
63 &InvalidPtrChecker::EnvpInvalidatingCall},
66 void postPreviousReturnInvalidatingCall(
const CallEvent &Call,
72 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
74 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
76 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
78 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
97 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
103 StringRef FunctionName)
const;
122 const
NoteTag *InvalidPtrChecker::createEnvInvalidationNote(
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];
165 void InvalidPtrChecker::EnvpInvalidatingCall(
const CallEvent &Call,
171 State =
State->add<InvalidMemoryRegions>(MainEnvPtr);
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);
182 void 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());
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()))
255 void InvalidPtrChecker::checkPostCall(
const CallEvent &Call,
261 if (GetEnvCall.matches(Call)) {
262 const MemRegion *Region =
Call.getReturnValue().getAsRegion();
264 State =
State->add<GetenvEnvPtrRegions>(Region);
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));
315 void InvalidPtrChecker::checkBeginFunction(
CheckerContext &C)
const {
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));
333 void 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");
360 bool ento::shouldRegisterInvalidPtrChecker(
const CheckerManager &) {
REGISTER_MAP_WITH_PROGRAMSTATE(PreviousCallResultMap, const FunctionDecl *, const MemRegion *) const NoteTag *InvalidPtrChecker
#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...
@ CLibrary
Match calls to functions from the C standard library.
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
bool Call(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
The JSON file list parser is used to communicate input to InstallAPI.