24 using namespace clang;
27 using PtrSet = llvm::ImmutableSet<SymbolRef>;
47 class InnerPointerChecker
48 :
public Checker<check::DeadSymbols, check::PostCall> {
51 InsertFn, PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn,
52 ShrinkToFitFn, SwapFn;
59 InnerPointerBRVisitor(
SymbolRef Sym) : PtrToBuf(Sym) {}
61 static void *getTag() {
66 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
67 ID.AddPointer(getTag());
70 std::shared_ptr<PathDiagnosticPiece> VisitNode(
const ExplodedNode *N,
78 RawPtrMapTy Map = State->get<RawPtrMap>();
79 for (
const auto Entry : Map) {
80 if (Entry.second.contains(Sym))
88 : AppendFn(
"append"), AssignFn(
"assign"), ClearFn(
"clear"),
89 CStrFn(
"c_str"), DataFn(
"data"), EraseFn(
"erase"), InsertFn(
"insert"),
90 PopBackFn(
"pop_back"), PushBackFn(
"push_back"), ReplaceFn(
"replace"),
91 ReserveFn(
"reserve"), ResizeFn(
"resize"),
92 ShrinkToFitFn(
"shrink_to_fit"), SwapFn(
"swap") {}
99 bool isInvalidatingMemberFunction(
const CallEvent &Call)
const;
124 bool InnerPointerChecker::isCalledOnStringObject(
126 const auto *ObjRegion =
131 QualType ObjTy = ObjRegion->getValueType();
139 bool InnerPointerChecker::isInvalidatingMemberFunction(
141 if (
const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
143 if (Opc == OO_Equal || Opc == OO_PlusEqual)
147 return (isa<CXXDestructorCall>(Call) || Call.
isCalled(AppendFn) ||
156 void InnerPointerChecker::markPtrSymbolsReleased(
const CallEvent &Call,
160 if (
const PtrSet *PS = State->get<RawPtrMap>(MR)) {
162 for (
const auto Symbol : *PS) {
167 State = State->remove<RawPtrMap>(MR);
173 void InnerPointerChecker::checkFunctionArguments(
const CallEvent &Call,
176 if (
const auto *FC = dyn_cast<AnyFunctionCall>(&Call)) {
181 for (
unsigned I = 0, E = FD->
getNumParams(); I != E; ++I) {
189 bool isaMemberOpCall = isa<CXXMemberOperatorCall>(FC);
190 unsigned ArgI = isaMemberOpCall ? I+1 : I;
192 SVal Arg = FC->getArgSVal(ArgI);
193 const auto *ArgRegion =
194 dyn_cast_or_null<TypedValueRegion>(Arg.
getAsRegion());
198 markPtrSymbolsReleased(Call, State, ArgRegion, C);
217 void InnerPointerChecker::checkPostCall(
const CallEvent &Call,
221 if (
const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
222 if (isCalledOnStringObject(ICall)) {
223 const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
233 const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
234 PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
236 Set = F.add(Set, Sym);
238 State = State->set<RawPtrMap>(ObjRegion, Set);
245 if (isInvalidatingMemberFunction(Call)) {
246 markPtrSymbolsReleased(Call, State, ObjRegion, C);
253 checkFunctionArguments(Call, State, C);
256 void InnerPointerChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
260 RawPtrMapTy RPM = State->get<RawPtrMap>();
261 for (
const auto Entry : RPM) {
265 State = State->remove<RawPtrMap>(Entry.first);
267 if (
const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) {
268 PtrSet CleanedUpSet = *OldSet;
269 for (
const auto Symbol : Entry.second) {
270 if (!SymReaper.
isLive(Symbol))
271 CleanedUpSet = F.remove(CleanedUpSet, Symbol);
273 State = CleanedUpSet.isEmpty()
274 ? State->remove<RawPtrMap>(Entry.first)
275 : State->set<RawPtrMap>(Entry.first, CleanedUpSet);
281 std::shared_ptr<PathDiagnosticPiece>
282 InnerPointerChecker::InnerPointerBRVisitor::VisitNode(
const ExplodedNode *N,
286 if (!isSymbolTracked(N->
getState(), PtrToBuf) ||
287 isSymbolTracked(PrevN->
getState(), PtrToBuf))
295 llvm::raw_svector_ostream OS(Buf);
296 OS <<
"Dangling inner pointer obtained here";
299 return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),
true,
305 namespace allocation_state {
308 return llvm::make_unique<InnerPointerChecker::InnerPointerBRVisitor>(Sym);
316 registerNewDeleteChecker(Mgr);
Represents a function declaration or definition.
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
Stmt - This represents one statement.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
llvm::ImmutableSet< SymbolRef > PtrSet
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
const ProgramStateRef & getState() const
const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
const bool wasInlined
If we are post visiting a call, this flag will be set if the call was inlined.
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...
bool isLiveRegion(const MemRegion *region)
const LocationContext * getLocationContext() const
SVal getReturnValue() const
Returns the return value of the call.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Represents a non-static C++ member function call, no matter how it is written.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Expr - This represents one expression.
virtual SVal getCXXThisVal() const
Returns the value of the implicit 'this' object.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
CHECKER * registerChecker(AT... Args)
Used to register checkers.
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...
This class represents a description of a function call using the number of arguments and the name of ...
const MemRegion * getAsRegion() const
const ParmVarDecl * getParamDecl(unsigned i) const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
A class responsible for cleaning up unused symbols.
Dataflow Directional Tag Classes.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
Represents an abstract call to a function or method along a particular path.
const ProgramStateRef & getState() const
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
bool isCalled(const CallDescription &CD) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
static llvm::ImmutableListFactory< const FieldRegion * > Factory
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()
bool isLive(SymbolRef sym)