25 using namespace clang;
35 class InnerPointerChecker
36 :
public Checker<check::DeadSymbols, check::PostCall> {
38 CallDescription AppendFn, AssignFn, ClearFn, CStrFn, DataFn, EraseFn,
39 InsertFn, PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn,
40 ShrinkToFitFn, SwapFn;
47 InnerPointerBRVisitor(
SymbolRef Sym) : PtrToBuf(Sym) {}
49 static void *getTag() {
54 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
55 ID.AddPointer(getTag());
58 virtual std::shared_ptr<PathDiagnosticPiece> VisitNode(
const ExplodedNode *N,
59 BugReporterContext &BRC,
60 BugReport &BR)
override;
65 RawPtrMapTy Map = State->get<RawPtrMap>();
66 for (
const auto Entry : Map) {
67 if (Entry.second.contains(Sym))
75 : AppendFn({
"std",
"basic_string",
"append"}),
76 AssignFn({
"std",
"basic_string",
"assign"}),
77 ClearFn({
"std",
"basic_string",
"clear"}),
78 CStrFn({
"std",
"basic_string",
"c_str"}),
79 DataFn({
"std",
"basic_string",
"data"}),
80 EraseFn({
"std",
"basic_string",
"erase"}),
81 InsertFn({
"std",
"basic_string",
"insert"}),
82 PopBackFn({
"std",
"basic_string",
"pop_back"}),
83 PushBackFn({
"std",
"basic_string",
"push_back"}),
84 ReplaceFn({
"std",
"basic_string",
"replace"}),
85 ReserveFn({
"std",
"basic_string",
"reserve"}),
86 ResizeFn({
"std",
"basic_string",
"resize"}),
87 ShrinkToFitFn({
"std",
"basic_string",
"shrink_to_fit"}),
88 SwapFn({
"std",
"basic_string",
"swap"}) {}
92 bool isInvalidatingMemberFunction(
const CallEvent &Call)
const;
97 const MemRegion *ObjRegion,
98 CheckerContext &C)
const;
104 CheckerContext &C)
const;
109 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
112 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C)
const;
117 bool InnerPointerChecker::isInvalidatingMemberFunction(
119 if (
const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
121 if (Opc == OO_Equal || Opc == OO_PlusEqual)
125 return (isa<CXXDestructorCall>(Call) || Call.isCalled(AppendFn) ||
126 Call.isCalled(AssignFn) || Call.isCalled(ClearFn) ||
127 Call.isCalled(EraseFn) || Call.isCalled(InsertFn) ||
128 Call.isCalled(PopBackFn) || Call.isCalled(PushBackFn) ||
129 Call.isCalled(ReplaceFn) || Call.isCalled(ReserveFn) ||
130 Call.isCalled(ResizeFn) || Call.isCalled(ShrinkToFitFn) ||
131 Call.isCalled(SwapFn));
134 void InnerPointerChecker::markPtrSymbolsReleased(
const CallEvent &Call,
137 CheckerContext &C)
const {
138 if (
const PtrSet *PS = State->get<RawPtrMap>(MR)) {
139 const Expr *Origin = Call.getOriginExpr();
140 for (
const auto Symbol : *PS) {
145 State = State->remove<RawPtrMap>(MR);
146 C.addTransition(State);
151 void InnerPointerChecker::checkFunctionArguments(
const CallEvent &Call,
153 CheckerContext &C)
const {
154 if (
const auto *FC = dyn_cast<AnyFunctionCall>(&Call)) {
159 for (
unsigned I = 0, E = FD->
getNumParams(); I != E; ++I) {
167 bool isaMemberOpCall = isa<CXXMemberOperatorCall>(FC);
168 unsigned ArgI = isaMemberOpCall ? I+1 : I;
170 SVal Arg = FC->getArgSVal(ArgI);
171 const auto *ArgRegion =
172 dyn_cast_or_null<TypedValueRegion>(Arg.getAsRegion());
176 markPtrSymbolsReleased(Call, State, ArgRegion, C);
195 void InnerPointerChecker::checkPostCall(
const CallEvent &Call,
196 CheckerContext &C)
const {
199 if (
const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
201 const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
202 ICall->getCXXThisVal().getAsRegion());
206 if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
207 SVal RawPtr = Call.getReturnValue();
208 if (
SymbolRef Sym = RawPtr.getAsSymbol(
true)) {
212 PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
213 const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
214 PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
215 assert(C.wasInlined || !Set.contains(Sym));
216 Set = F.add(Set, Sym);
218 State = State->set<RawPtrMap>(ObjRegion, Set);
219 C.addTransition(State);
225 if (isInvalidatingMemberFunction(Call)) {
226 markPtrSymbolsReleased(Call, State, ObjRegion, C);
232 checkFunctionArguments(Call, State, C);
235 void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,
236 CheckerContext &C)
const {
238 PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
239 RawPtrMapTy RPM = State->get<RawPtrMap>();
240 for (
const auto Entry : RPM) {
241 if (!SymReaper.isLiveRegion(Entry.first)) {
244 State = State->remove<RawPtrMap>(Entry.first);
246 if (
const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) {
247 PtrSet CleanedUpSet = *OldSet;
248 for (
const auto Symbol : Entry.second) {
249 if (!SymReaper.isLive(Symbol))
250 CleanedUpSet = F.remove(CleanedUpSet, Symbol);
252 State = CleanedUpSet.isEmpty()
253 ? State->remove<RawPtrMap>(Entry.first)
254 : State->set<RawPtrMap>(Entry.first, CleanedUpSet);
257 C.addTransition(State);
262 namespace allocation_state {
265 return llvm::make_unique<InnerPointerChecker::InnerPointerBRVisitor>(Sym);
269 RawPtrMapTy Map = State->get<RawPtrMap>();
270 for (
const auto Entry : Map) {
271 if (Entry.second.contains(Sym)) {
282 std::shared_ptr<PathDiagnosticPiece>
283 InnerPointerChecker::InnerPointerBRVisitor::VisitNode(
const ExplodedNode *N,
286 if (!isSymbolTracked(N->
getState(), PtrToBuf) ||
296 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
297 QualType ObjTy = TypedRegion->getValueType();
300 llvm::raw_svector_ostream
OS(Buf);
301 OS <<
"Pointer to inner buffer of '" << ObjTy.getAsString()
302 <<
"' obtained here";
305 return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),
true,
Represents a function declaration or definition.
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
const SymExpr * SymbolRef
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
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...
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
This represents one expression.
bool isConstQualified() const
Determine whether this type is const-qualified.
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
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)
This class provides an interface through which checkers can create individual bug reports...
bool isInStdNamespace() const
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
SourceManager & getSourceManager()
TypedRegion - An abstract class representing regions that are typed.