30bool isRefcountedStringsHack(
const VarDecl *
V) {
32 auto safeClass = [](
const std::string &className) {
33 return className ==
"String" || className ==
"AtomString" ||
34 className ==
"UniquedString" || className ==
"Identifier";
52 const VarDecl *Guardian{
nullptr};
54 explicit GuardianVisitor(
const VarDecl *Guardian) : Guardian(Guardian) {
60 if (
auto *VarRef = dyn_cast<DeclRefExpr>(BO->
getLHS())) {
61 if (VarRef->getDecl() == Guardian)
70 if (Ctor->isMoveConstructor() && CE->
getNumArgs() == 1) {
72 if (
auto *VarRef = dyn_cast<DeclRefExpr>(Arg)) {
73 if (VarRef->getDecl() == Guardian)
83 if (MethodName ==
"swap" || MethodName ==
"leakRef" ||
84 MethodName ==
"releaseNonNull") {
86 if (
auto *VarRef = dyn_cast<DeclRefExpr>(ThisArg)) {
87 if (VarRef->getDecl() == Guardian)
98 if (
auto *VarRef = dyn_cast<DeclRefExpr>(ThisArg)) {
99 if (VarRef->getDecl() == Guardian)
107bool isGuardedScopeEmbeddedInGuardianScope(
const VarDecl *Guarded,
108 const VarDecl *MaybeGuardian) {
110 assert(MaybeGuardian);
115 const CompoundStmt *guardiansClosestCompStmtAncestor =
nullptr;
120 !guardianAncestors.
empty();
125 for (
auto &guardianAncestor : guardianAncestors) {
126 if (
auto *CStmtParentAncestor = guardianAncestor.get<
CompoundStmt>()) {
127 guardiansClosestCompStmtAncestor = CStmtParentAncestor;
131 if (guardiansClosestCompStmtAncestor)
135 if (!guardiansClosestCompStmtAncestor)
142 !guardedVarAncestors.
empty();
147 for (
auto &guardedVarAncestor : guardedVarAncestors) {
148 if (
auto *CStmtAncestor = guardedVarAncestor.get<
CompoundStmt>()) {
149 if (!FirstCompondStmt) {
150 FirstCompondStmt = CStmtAncestor;
153 if (CStmtAncestor == guardiansClosestCompStmtAncestor) {
154 GuardianVisitor guardianVisitor(MaybeGuardian);
155 auto *GuardedScope =
const_cast<CompoundStmt *
>(FirstCompondStmt);
156 return guardianVisitor.TraverseCompoundStmt(GuardedScope);
165class RawPtrRefLocalVarsChecker
166 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
172 RawPtrRefLocalVarsChecker(
const char *description)
173 : Bug(this, description,
"WebKit coding guidelines") {}
176 virtual const char *ptrKind()
const = 0;
186 const RawPtrRefLocalVarsChecker *
Checker;
187 Decl *DeclWithIssue{
nullptr};
191 explicit LocalVisitor(
const RawPtrRefLocalVarsChecker *
Checker)
194 ShouldVisitTemplateInstantiations =
true;
195 ShouldVisitImplicitCode =
false;
198 bool TraverseDecl(
Decl *
D)
override {
200 if (
D && (isa<FunctionDecl>(
D) || isa<ObjCMethodDecl>(
D)))
205 bool VisitVarDecl(
VarDecl *
V)
override {
206 auto *
Init =
V->getInit();
207 if (
Init &&
V->isLocalVarDecl())
214 if (
auto *VarRef = dyn_cast<DeclRefExpr>(BO->
getLHS())) {
215 if (
auto *
V = dyn_cast<VarDecl>(VarRef->getDecl()))
222 bool TraverseIfStmt(
IfStmt *IS)
override {
224 return DynamicRecursiveASTVisitor::TraverseIfStmt(IS);
228 bool TraverseForStmt(
ForStmt *FS)
override {
230 return DynamicRecursiveASTVisitor::TraverseForStmt(FS);
236 return DynamicRecursiveASTVisitor::TraverseCXXForRangeStmt(FRS);
240 bool TraverseWhileStmt(
WhileStmt *WS)
override {
242 return DynamicRecursiveASTVisitor::TraverseWhileStmt(WS);
248 return DynamicRecursiveASTVisitor::TraverseCompoundStmt(CS);
253 LocalVisitor visitor(
this);
258 const Decl *DeclWithIssue)
const {
259 if (shouldSkipVarDecl(
V))
262 std::optional<bool> IsUncountedPtr =
isUnsafePtr(
V->getType());
263 if (IsUncountedPtr && *IsUncountedPtr) {
266 [&](
const clang::Expr *InitArgOrigin,
bool IsSafe) {
267 if (!InitArgOrigin || IsSafe)
270 if (isa<CXXThisExpr>(InitArgOrigin))
273 if (isa<CXXNullPtrLiteralExpr>(InitArgOrigin))
276 if (isa<IntegerLiteral>(InitArgOrigin))
285 if (
auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
286 if (
auto *MaybeGuardian =
287 dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
288 const auto *MaybeGuardianArgType =
289 MaybeGuardian->getType().getTypePtr();
290 if (MaybeGuardianArgType) {
291 const CXXRecordDecl *const MaybeGuardianArgCXXRecord =
292 MaybeGuardianArgType->getAsCXXRecordDecl();
293 if (MaybeGuardianArgCXXRecord) {
294 if (MaybeGuardian->isLocalVarDecl() &&
295 (isRefCounted(MaybeGuardianArgCXXRecord) ||
296 isCheckedPtr(MaybeGuardianArgCXXRecord) ||
297 isRefcountedStringsHack(MaybeGuardian)) &&
298 isGuardedScopeEmbeddedInGuardianScope(
306 if (isa<ParmVarDecl>(MaybeGuardian))
315 reportBug(
V,
Value, DeclWithIssue);
319 bool shouldSkipVarDecl(
const VarDecl *
V)
const {
325 const Decl *DeclWithIssue)
const {
328 llvm::raw_svector_ostream Os(Buf);
330 if (dyn_cast<ParmVarDecl>(
V)) {
331 Os <<
"Assignment to an " << ptrKind() <<
" parameter ";
336 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
340 if (
V->hasLocalStorage())
341 Os <<
"Local variable ";
342 else if (
V->isStaticLocal())
343 Os <<
"Static local variable ";
344 else if (
V->hasGlobalStorage())
345 Os <<
"Global variable ";
349 Os <<
" is " << ptrKind() <<
" and unsafe.";
352 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
353 Report->addRange(
V->getSourceRange());
354 Report->setDeclWithIssue(DeclWithIssue);
360class UncountedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
362 UncountedLocalVarsChecker()
363 : RawPtrRefLocalVarsChecker(
"Uncounted raw pointer or reference not "
364 "provably backed by ref-counted variable") {}
368 const char *ptrKind() const final {
return "uncounted"; }
371class UncheckedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
373 UncheckedLocalVarsChecker()
374 : RawPtrRefLocalVarsChecker(
"Unchecked raw pointer or reference not "
375 "provably backed by checked variable") {}
379 const char *ptrKind() const final {
return "unchecked"; }
384void ento::registerUncountedLocalVarsChecker(
CheckerManager &Mgr) {
388bool ento::shouldRegisterUncountedLocalVarsChecker(
const CheckerManager &) {
392void ento::registerUncheckedLocalVarsChecker(
CheckerManager &Mgr) {
396bool ento::shouldRegisterUncheckedLocalVarsChecker(
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)
Represents a call to a C++ constructor.
Expr * getArg(unsigned Arg)
Return the specified argument.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Represents a call to a member function that may be written either with member call syntax (e....
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
A call to an overloaded operator written using operator syntax.
static bool isAssignmentOp(OverloadedOperatorKind Opc)
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
CompoundStmt - This represents a group of statements like { stmt stmt }.
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
Recursive AST visitor that supports extension via dynamic dispatch.
virtual bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
bool isACallToEnsureFn(const Expr *E) const
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
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.
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.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
const FunctionProtoType * T
std::optional< bool > isUncountedPtr(const QualType 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)
std::optional< bool > isUnsafePtr(const QualType T)
bool isConstOwnerPtrMemberExpr(const clang::Expr *E)
std::optional< bool > isUncheckedPtr(const QualType T)