24 using namespace clang;
34 class InnerPointerChecker
35 :
public Checker<check::DeadSymbols, check::PostCall> {
38 InsertFn, PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn,
39 ShrinkToFitFn, SwapFn;
46 InnerPointerBRVisitor(
SymbolRef Sym) : PtrToBuf(Sym) {}
48 static void *getTag() {
53 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
54 ID.AddPointer(getTag());
58 VisitNode(
const ExplodedNode *N, BugReporterContext &BRC,
59 PathSensitiveBugReport &BR)
override;
64 RawPtrMapTy Map = State->get<RawPtrMap>();
65 for (
const auto &Entry : Map) {
66 if (Entry.second.contains(Sym))
74 : AppendFn({
"std",
"basic_string",
"append"}),
75 AssignFn({
"std",
"basic_string",
"assign"}),
76 ClearFn({
"std",
"basic_string",
"clear"}),
77 CStrFn({
"std",
"basic_string",
"c_str"}),
78 DataFn({
"std",
"basic_string",
"data"}),
79 EraseFn({
"std",
"basic_string",
"erase"}),
80 InsertFn({
"std",
"basic_string",
"insert"}),
81 PopBackFn({
"std",
"basic_string",
"pop_back"}),
82 PushBackFn({
"std",
"basic_string",
"push_back"}),
83 ReplaceFn({
"std",
"basic_string",
"replace"}),
84 ReserveFn({
"std",
"basic_string",
"reserve"}),
85 ResizeFn({
"std",
"basic_string",
"resize"}),
86 ShrinkToFitFn({
"std",
"basic_string",
"shrink_to_fit"}),
87 SwapFn({
"std",
"basic_string",
"swap"}) {}
91 bool isInvalidatingMemberFunction(
const CallEvent &Call)
const;
96 const MemRegion *ObjRegion,
97 CheckerContext &C)
const;
103 CheckerContext &C)
const;
108 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
111 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C)
const;
116 bool InnerPointerChecker::isInvalidatingMemberFunction(
118 if (
const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
120 if (Opc == OO_Equal || Opc == OO_PlusEqual)
124 return (isa<CXXDestructorCall>(Call) || Call.isCalled(AppendFn) ||
125 Call.isCalled(AssignFn) || Call.isCalled(ClearFn) ||
126 Call.isCalled(EraseFn) || Call.isCalled(InsertFn) ||
127 Call.isCalled(PopBackFn) || Call.isCalled(PushBackFn) ||
128 Call.isCalled(ReplaceFn) || Call.isCalled(ReserveFn) ||
129 Call.isCalled(ResizeFn) || Call.isCalled(ShrinkToFitFn) ||
130 Call.isCalled(SwapFn));
133 void InnerPointerChecker::markPtrSymbolsReleased(
const CallEvent &Call,
136 CheckerContext &C)
const {
137 if (
const PtrSet *PS = State->get<RawPtrMap>(MR)) {
138 const Expr *Origin = Call.getOriginExpr();
139 for (
const auto Symbol : *PS) {
144 State = State->remove<RawPtrMap>(MR);
145 C.addTransition(State);
150 void InnerPointerChecker::checkFunctionArguments(
const CallEvent &Call,
152 CheckerContext &C)
const {
153 if (
const auto *FC = dyn_cast<AnyFunctionCall>(&Call)) {
158 for (
unsigned I = 0, E = FD->
getNumParams(); I != E; ++I) {
166 bool isaMemberOpCall = isa<CXXMemberOperatorCall>(FC);
167 unsigned ArgI = isaMemberOpCall ? I+1 : I;
169 SVal Arg = FC->getArgSVal(ArgI);
170 const auto *ArgRegion =
171 dyn_cast_or_null<TypedValueRegion>(Arg.getAsRegion());
175 markPtrSymbolsReleased(Call, State, ArgRegion, C);
194 void InnerPointerChecker::checkPostCall(
const CallEvent &Call,
195 CheckerContext &C)
const {
198 if (
const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
200 const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
201 ICall->getCXXThisVal().getAsRegion());
205 if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
206 SVal RawPtr = Call.getReturnValue();
207 if (
SymbolRef Sym = RawPtr.getAsSymbol(
true)) {
211 PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
212 const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
213 PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
214 assert(C.wasInlined || !Set.contains(Sym));
215 Set = F.add(Set, Sym);
217 State = State->set<RawPtrMap>(ObjRegion, Set);
218 C.addTransition(State);
224 if (isInvalidatingMemberFunction(Call)) {
225 markPtrSymbolsReleased(Call, State, ObjRegion, C);
231 checkFunctionArguments(Call, State, C);
234 void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,
235 CheckerContext &C)
const {
237 PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
238 RawPtrMapTy RPM = State->get<RawPtrMap>();
239 for (
const auto &Entry : RPM) {
240 if (!SymReaper.isLiveRegion(Entry.first)) {
243 State = State->remove<RawPtrMap>(Entry.first);
245 if (
const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) {
246 PtrSet CleanedUpSet = *OldSet;
247 for (
const auto Symbol : Entry.second) {
248 if (!SymReaper.isLive(Symbol))
249 CleanedUpSet = F.remove(CleanedUpSet, Symbol);
251 State = CleanedUpSet.isEmpty()
252 ? State->remove<RawPtrMap>(Entry.first)
253 : State->set<RawPtrMap>(Entry.first, CleanedUpSet);
256 C.addTransition(State);
261 namespace allocation_state {
264 return std::make_unique<InnerPointerChecker::InnerPointerBRVisitor>(Sym);
268 RawPtrMapTy Map = State->get<RawPtrMap>();
269 for (
const auto &Entry : Map) {
270 if (Entry.second.contains(Sym)) {
283 if (!isSymbolTracked(N->
getState(), PtrToBuf) ||
293 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
294 QualType ObjTy = TypedRegion->getValueType();
297 llvm::raw_svector_ostream
OS(Buf);
298 OS <<
"Pointer to inner buffer of '" << ObjTy.getAsString()
299 <<
"' obtained here";
302 return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),
true);
310 bool ento::shouldRegisterInnerPointerChecker(
const LangOptions &LO) {
Represents a function declaration or definition.
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
Stmt - This represents one statement.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)
'Sym' represents a pointer to the inner buffer of a container object.
const ProgramStateRef & getState() const
const SymExpr * SymbolRef
bool isReferenceType() const
std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)
This function provides an additional visitor that augments the bug report with information relevant t...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
This class represents a description of a function call using the number of arguments and the name of ...
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
This represents one expression.
bool isConstQualified() const
Determine whether this type is const-qualified.
const SourceManager & getSourceManager() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set type Name and registers the factory for such sets in the program state...
const ParmVarDecl * getParamDecl(unsigned i) const
Dataflow Directional Tag Classes.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
bool isInStdNamespace() const
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
TypedRegion - An abstract class representing regions that are typed.