30class InvalidPtrChecker
31 :
public Checker<check::Location, check::BeginFunction, check::PostCall> {
37 using HandlerFn = void (InvalidPtrChecker::*)(
const CallEvent &
Call,
42 {{{
"setenv"}, 3}, &InvalidPtrChecker::EnvpInvalidatingCall},
43 {{{
"unsetenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
44 {{{
"putenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
45 {{{
"_putenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
46 {{{
"_wputenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
49 void postPreviousReturnInvalidatingCall(
const CallEvent &Call,
54 {{{
"getenv"}, 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
56 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
58 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
60 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
62 &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
77 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
94void InvalidPtrChecker::EnvpInvalidatingCall(const
CallEvent &Call,
96 StringRef FunctionName = Call.getCalleeIdentifier()->getName();
98 const MemRegion *SymbolicEnvPtrRegion = State->get<EnvPtrRegion>();
99 if (!SymbolicEnvPtrRegion)
102 State = State->add<InvalidMemoryRegions>(SymbolicEnvPtrRegion);
105 C.getNoteTag([SymbolicEnvPtrRegion, FunctionName](
109 Out <<
'\'' << FunctionName
110 <<
"' call may invalidate the environment parameter of 'main'";
113 C.addTransition(State,
Note);
116void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
124 if (
const MemRegion *
const *Reg = State->get<PreviousCallResultMap>(FD)) {
126 State = State->add<InvalidMemoryRegions>(PrevReg);
128 llvm::raw_ostream &Out) {
133 Out <<
"' call may invalidate the result of the previous " <<
'\'';
140 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
144 CE, LCtx, CE->getType(),
C.blockCount());
145 State = State->BindExpr(CE, LCtx, RetVal);
148 const auto *SymRegOfRetVal = cast<SymbolicRegion>(RetVal.
getAsRegion());
150 const_cast<MemRegion *
>(SymRegOfRetVal->getBaseRegion());
151 State = State->set<PreviousCallResultMap>(FD, MR);
154 const NoteTag *PreviousCallNote =
158 Out <<
'\'' <<
"'previous function call was here" <<
'\'';
161 C.addTransition(State,
Node, PreviousCallNote);
168 if (State->contains<InvalidMemoryRegions>(Reg))
173 const auto *SRV = dyn_cast<SymbolRegionValue>(SymBase->getSymbol());
176 Reg = SRV->getRegion();
177 if (
const auto *VarReg = dyn_cast<VarRegion>(SRV->getRegion()))
186void InvalidPtrChecker::checkPostCall(
const CallEvent &Call,
189 if (
const auto *Handler = EnvpInvalidatingFunctions.lookup(Call))
190 (this->**Handler)(Call,
C);
193 if (
const auto *Handler = PreviousCallInvalidatingFunctions.lookup(Call))
194 (this->**Handler)(
Call,
C);
204 for (
unsigned I = 0, NumArgs =
Call.getNumArgs(); I < NumArgs; ++I) {
206 if (
const auto *SR = dyn_cast_or_null<SymbolicRegion>(
207 Call.getArgSVal(I).getAsRegion())) {
208 if (
const MemRegion *InvalidatedSymbolicBase =
209 findInvalidatedSymbolicBase(State, SR)) {
215 llvm::raw_svector_ostream Out(Msg);
216 Out <<
"use of invalidated pointer '";
217 Call.getArgExpr(I)->printPretty(Out,
nullptr,
218 C.getASTContext().getPrintingPolicy());
219 Out <<
"' in a function call";
222 std::make_unique<PathSensitiveBugReport>(BT, Out.str(), ErrorNode);
223 Report->markInteresting(InvalidatedSymbolicBase);
224 Report->addRange(
Call.getArgSourceRange(I));
225 C.emitReport(std::move(Report));
236 const auto *FD = dyn_cast<FunctionDecl>(
C.getLocationContext()->getDecl());
237 if (!FD || FD->param_size() != 3 || !FD->isMain())
242 State->getRegion(FD->parameters()[2],
C.getLocationContext());
246 C.addTransition(State->set<EnvPtrRegion>(EnvpReg));
250void InvalidPtrChecker::checkLocation(
SVal Loc,
bool isLoad,
const Stmt *S,
255 const MemRegion *InvalidatedSymbolicBase =
257 if (!InvalidatedSymbolicBase)
264 auto Report = std::make_unique<PathSensitiveBugReport>(
265 BT,
"dereferencing an invalid pointer", ErrorNode);
266 Report->markInteresting(InvalidatedSymbolicBase);
267 C.emitReport(std::move(Report));
274bool 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.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
Stmt - This represents one statement.
An immutable map from CallDescriptions to arbitrary data.
Represents an abstract call to a function or method along a particular path.
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.
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)
@ C
Languages that the frontend can parse and compile.