30bool isRefcountedStringsHack(
const VarDecl *
V) {
32 auto safeClass = [](
const std::string &className) {
33 return className ==
"String" || className ==
"AtomString" ||
34 className ==
"UniquedString" || className ==
"Identifier";
51bool isGuardedScopeEmbeddedInGuardianScope(
const VarDecl *Guarded,
54 assert(MaybeGuardian);
59 const CompoundStmt *guardiansClosestCompStmtAncestor =
nullptr;
64 !guardianAncestors.
empty();
69 for (
auto &guardianAncestor : guardianAncestors) {
70 if (
auto *CStmtParentAncestor = guardianAncestor.get<
CompoundStmt>()) {
71 guardiansClosestCompStmtAncestor = CStmtParentAncestor;
75 if (guardiansClosestCompStmtAncestor)
79 if (!guardiansClosestCompStmtAncestor)
84 bool HaveSkippedFirstCompoundStmt =
false;
86 !guardedVarAncestors.
empty();
91 for (
auto &guardedVarAncestor : guardedVarAncestors) {
92 if (
auto *CStmtAncestor = guardedVarAncestor.get<
CompoundStmt>()) {
93 if (!HaveSkippedFirstCompoundStmt) {
94 HaveSkippedFirstCompoundStmt =
true;
97 if (CStmtAncestor == guardiansClosestCompStmtAncestor)
106class UncountedLocalVarsChecker
107 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
109 "Uncounted raw pointer or reference not provably backed by "
110 "ref-counted variable",
111 "WebKit coding guidelines"};
123 const UncountedLocalVarsChecker *
Checker;
129 explicit LocalVisitor(
const UncountedLocalVarsChecker *
Checker)
134 bool shouldVisitTemplateInstantiations()
const {
return true; }
135 bool shouldVisitImplicitCode()
const {
return false; }
138 auto *
Init =
V->getInit();
139 if (
Init &&
V->isLocalVarDecl())
146 if (
auto *VarRef = dyn_cast<DeclRefExpr>(BO->
getLHS())) {
147 if (
auto *
V = dyn_cast<VarDecl>(VarRef->getDecl()))
154 bool TraverseIfStmt(
IfStmt *IS) {
156 return Base::TraverseIfStmt(IS);
160 bool TraverseForStmt(
ForStmt *FS) {
162 return Base::TraverseForStmt(FS);
168 return Base::TraverseCXXForRangeStmt(FRS);
174 return Base::TraverseWhileStmt(WS);
180 return Base::TraverseCompoundStmt(CS);
185 LocalVisitor visitor(
this);
190 if (shouldSkipVarDecl(
V))
193 const auto *ArgType =
V->getType().getTypePtr();
198 if (IsUncountedPtr && *IsUncountedPtr) {
201 [&](
const clang::Expr *InitArgOrigin,
bool IsSafe) {
205 if (isa<CXXThisExpr>(InitArgOrigin))
208 if (isa<CXXNullPtrLiteralExpr>(InitArgOrigin))
211 if (isa<IntegerLiteral>(InitArgOrigin))
214 if (
auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
215 if (
auto *MaybeGuardian =
216 dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
217 const auto *MaybeGuardianArgType =
218 MaybeGuardian->getType().getTypePtr();
219 if (MaybeGuardianArgType) {
220 const CXXRecordDecl *const MaybeGuardianArgCXXRecord =
221 MaybeGuardianArgType->getAsCXXRecordDecl();
222 if (MaybeGuardianArgCXXRecord) {
223 if (MaybeGuardian->isLocalVarDecl() &&
224 (isRefCounted(MaybeGuardianArgCXXRecord) ||
225 isRefcountedStringsHack(MaybeGuardian)) &&
226 isGuardedScopeEmbeddedInGuardianScope(
234 if (isa<ParmVarDecl>(MaybeGuardian))
247 bool shouldSkipVarDecl(
const VarDecl *
V)
const {
255 llvm::raw_svector_ostream Os(Buf);
257 if (dyn_cast<ParmVarDecl>(
V)) {
258 Os <<
"Assignment to an uncounted parameter ";
263 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
264 Report->addRange(
Value->getSourceRange());
267 if (
V->hasLocalStorage())
268 Os <<
"Local variable ";
269 else if (
V->isStaticLocal())
270 Os <<
"Static local variable ";
271 else if (
V->hasGlobalStorage())
272 Os <<
"Global variable ";
276 Os <<
" is uncounted and unsafe.";
279 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
280 Report->addRange(
V->getSourceRange());
287void ento::registerUncountedLocalVarsChecker(
CheckerManager &Mgr) {
291bool ento::shouldRegisterUncountedLocalVarsChecker(
const CheckerManager &) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::SourceLocation class and associated facilities.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isAssignmentOp(Opcode Opc)
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
CompoundStmt - This represents a group of statements like { stmt stmt }.
ASTContext & getASTContext() const LLVM_READONLY
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
This represents one expression.
ForStmt - This represents a 'for (init;cond;inc)' stmt.
IfStmt - This represents an if/then/else.
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
The top declaration context.
An inter-procedural analysis facility that detects functions with "trivial" behavior with respect to ...
bool isTrivial(const Decl *D) const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isPointerType() const
bool isReferenceType() const
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Represents a variable declaration or definition.
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
WhileStmt - This represents a 'while' stmt.
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
The JSON file list parser is used to communicate input to InstallAPI.
std::optional< bool > isUncountedPtr(const Type *T)
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
const FunctionProtoType * T
bool tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj, std::function< bool(const clang::Expr *, bool)> callback)
This function de-facto defines a set of transformations that we consider safe (in heuristical sense).
std::string safeGetName(const T *ASTNode)