31bool isRefcountedStringsHack(
const VarDecl *
V) {
33 auto safeClass = [](
const std::string &className) {
34 return className ==
"String" || className ==
"AtomString" ||
35 className ==
"UniquedString" || className ==
"Identifier";
39 if (
auto *CXXRD =
T->getAsCXXRecordDecl()) {
43 if (
T->isPointerType() ||
T->isReferenceType()) {
44 if (
auto *CXXRD =
T->getPointeeCXXRecordDecl()) {
53 const VarDecl *Guardian{
nullptr};
55 explicit GuardianVisitor(
const VarDecl *Guardian) : Guardian(Guardian) {
59 bool VisitBinaryOperator(BinaryOperator *BO)
override {
61 if (
auto *VarRef = dyn_cast<DeclRefExpr>(BO->
getLHS())) {
62 if (VarRef->getDecl() == Guardian)
69 bool VisitCXXConstructExpr(CXXConstructExpr *CE)
override {
71 if (Ctor->isMoveConstructor() && CE->
getNumArgs() == 1) {
73 if (
auto *VarRef = dyn_cast<DeclRefExpr>(Arg)) {
74 if (VarRef->getDecl() == Guardian)
82 bool VisitCXXMemberCallExpr(CXXMemberCallExpr *MCE)
override {
84 if (MethodName ==
"swap" || MethodName ==
"leakRef" ||
85 MethodName ==
"releaseNonNull" || MethodName ==
"clear") {
87 if (
auto *VarRef = dyn_cast<DeclRefExpr>(ThisArg)) {
88 if (VarRef->getDecl() == Guardian)
95 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *OCE)
override {
99 if (
auto *VarRef = dyn_cast<DeclRefExpr>(ThisArg)) {
100 if (VarRef->getDecl() == Guardian)
108bool isGuardedScopeEmbeddedInGuardianScope(
const VarDecl *Guarded,
109 const VarDecl *MaybeGuardian) {
111 assert(MaybeGuardian);
116 const CompoundStmt *guardiansClosestCompStmtAncestor =
nullptr;
121 !guardianAncestors.
empty();
126 for (
auto &guardianAncestor : guardianAncestors) {
127 if (
auto *CStmtParentAncestor = guardianAncestor.get<
CompoundStmt>()) {
128 guardiansClosestCompStmtAncestor = CStmtParentAncestor;
132 if (guardiansClosestCompStmtAncestor)
136 if (!guardiansClosestCompStmtAncestor)
143 !guardedVarAncestors.
empty();
148 for (
auto &guardedVarAncestor : guardedVarAncestors) {
149 if (
auto *CStmtAncestor = guardedVarAncestor.get<
CompoundStmt>()) {
150 if (!FirstCompondStmt) {
151 FirstCompondStmt = CStmtAncestor;
154 if (CStmtAncestor == guardiansClosestCompStmtAncestor) {
155 GuardianVisitor guardianVisitor(MaybeGuardian);
156 auto *GuardedScope =
const_cast<CompoundStmt *
>(FirstCompondStmt);
157 return guardianVisitor.TraverseCompoundStmt(GuardedScope);
166class RawPtrRefLocalVarsChecker
167 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
169 EnsureFunctionAnalysis EFA;
172 mutable BugReporter *BR;
173 mutable std::optional<RetainTypeChecker> RTC;
176 RawPtrRefLocalVarsChecker(
const char *description)
177 : Bug(this, description,
"WebKit coding guidelines") {}
179 virtual std::optional<bool>
isUnsafePtr(
const QualType
T)
const = 0;
180 virtual bool isSafePtr(
const CXXRecordDecl *)
const = 0;
181 virtual bool isSafePtrType(
const QualType)
const = 0;
182 virtual bool isSafeExpr(
const Expr *)
const {
return false; }
183 virtual bool isSafeDecl(
const Decl *)
const {
return false; }
184 virtual const char *ptrKind()
const = 0;
186 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
187 BugReporter &BRArg)
const {
194 const RawPtrRefLocalVarsChecker *Checker;
195 Decl *DeclWithIssue{
nullptr};
197 TrivialFunctionAnalysis TFA;
199 explicit LocalVisitor(
const RawPtrRefLocalVarsChecker *Checker)
202 ShouldVisitTemplateInstantiations =
true;
203 ShouldVisitImplicitCode =
false;
206 bool TraverseDecl(Decl *D)
override {
207 llvm::SaveAndRestore SavedDecl(DeclWithIssue);
213 bool VisitTypedefDecl(TypedefDecl *TD)
override {
215 Checker->RTC->visitTypedef(TD);
219 bool VisitVarDecl(VarDecl *
V)
override {
220 auto *
Init =
V->getInit();
221 if (
Init &&
V->isLocalVarDecl())
222 Checker->visitVarDecl(
V,
Init, DeclWithIssue);
226 bool VisitBinaryOperator(BinaryOperator *BO)
override {
228 if (
auto *VarRef = dyn_cast<DeclRefExpr>(BO->
getLHS())) {
229 if (
auto *
V = dyn_cast<VarDecl>(VarRef->getDecl()))
230 Checker->visitVarDecl(
V, BO->
getRHS(), DeclWithIssue);
236 bool TraverseIfStmt(IfStmt *IS)
override {
238 return DynamicRecursiveASTVisitor::TraverseIfStmt(IS);
242 bool TraverseForStmt(ForStmt *FS)
override {
244 return DynamicRecursiveASTVisitor::TraverseForStmt(FS);
248 bool TraverseCXXForRangeStmt(CXXForRangeStmt *FRS)
override {
250 return DynamicRecursiveASTVisitor::TraverseCXXForRangeStmt(FRS);
254 bool TraverseWhileStmt(WhileStmt *WS)
override {
256 return DynamicRecursiveASTVisitor::TraverseWhileStmt(WS);
262 return DynamicRecursiveASTVisitor::TraverseCompoundStmt(CS);
266 bool TraverseClassTemplateDecl(ClassTemplateDecl *Decl)
override {
269 return DynamicRecursiveASTVisitor::TraverseClassTemplateDecl(Decl);
273 LocalVisitor visitor(
this);
275 RTC->visitTranslationUnitDecl(TUD);
276 visitor.TraverseDecl(
const_cast<TranslationUnitDecl *
>(TUD));
279 void visitVarDecl(
const VarDecl *
V,
const Expr *
Value,
280 const Decl *DeclWithIssue)
const {
281 if (shouldSkipVarDecl(
V))
284 std::optional<bool> IsUncountedPtr =
isUnsafePtr(
V->getType());
285 if (IsUncountedPtr && *IsUncountedPtr) {
288 [&](
const clang::CXXRecordDecl *
Record) {
291 [&](
const clang::QualType
Type) {
return isSafePtrType(
Type); },
292 [&](
const clang::Decl *D) {
return isSafeDecl(D); },
293 [&](
const clang::Expr *InitArgOrigin,
bool IsSafe) {
294 if (!InitArgOrigin || IsSafe)
309 if (EFA.isACallToEnsureFn(InitArgOrigin))
312 if (isSafeExpr(InitArgOrigin))
315 if (
auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
316 if (
auto *MaybeGuardian =
317 dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
318 const auto *MaybeGuardianArgType =
320 if (MaybeGuardianArgType) {
321 const CXXRecordDecl *
const MaybeGuardianArgCXXRecord =
322 MaybeGuardianArgType->getAsCXXRecordDecl();
323 if (MaybeGuardianArgCXXRecord) {
326 isRefcountedStringsHack(MaybeGuardian)) &&
327 isGuardedScopeEmbeddedInGuardianScope(
344 reportBug(
V,
Value, DeclWithIssue);
348 bool shouldSkipVarDecl(
const VarDecl *
V)
const {
352 return BR->getSourceManager().isInSystemHeader(
V->getLocation());
355 void reportBug(
const VarDecl *
V,
const Expr *
Value,
356 const Decl *DeclWithIssue)
const {
358 SmallString<100> Buf;
359 llvm::raw_svector_ostream Os(Buf);
362 Os <<
"Assignment to an " << ptrKind() <<
" parameter ";
366 PathDiagnosticLocation BSLoc(
Value->getExprLoc(), BR->getSourceManager());
367 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
369 BR->emitReport(std::move(
Report));
371 if (
V->hasLocalStorage())
372 Os <<
"Local variable ";
373 else if (
V->isStaticLocal())
374 Os <<
"Static local variable ";
375 else if (
V->hasGlobalStorage())
376 Os <<
"Global variable ";
380 Os <<
" is " << ptrKind() <<
" and unsafe.";
382 PathDiagnosticLocation BSLoc(
V->getLocation(), BR->getSourceManager());
383 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
384 Report->addRange(
V->getSourceRange());
385 Report->setDeclWithIssue(DeclWithIssue);
386 BR->emitReport(std::move(
Report));
391class UncountedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
393 UncountedLocalVarsChecker()
394 : RawPtrRefLocalVarsChecker(
"Uncounted raw pointer or reference not "
395 "provably backed by ref-counted variable") {}
396 std::optional<bool>
isUnsafePtr(
const QualType
T)
const final {
402 bool isSafePtrType(
const QualType
type)
const final {
405 const char *ptrKind() const final {
return "uncounted"; }
408class UncheckedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
410 UncheckedLocalVarsChecker()
411 : RawPtrRefLocalVarsChecker(
"Unchecked raw pointer or reference not "
412 "provably backed by checked variable") {}
413 std::optional<bool>
isUnsafePtr(
const QualType
T)
const final {
419 bool isSafePtrType(
const QualType
type)
const final {
422 bool isSafeExpr(
const Expr *E)
const final {
425 const char *ptrKind() const final {
return "unchecked"; }
428class UnretainedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
430 UnretainedLocalVarsChecker()
431 : RawPtrRefLocalVarsChecker(
"Unretained raw pointer or reference not "
432 "provably backed by a RetainPtr") {
433 RTC = RetainTypeChecker();
435 std::optional<bool>
isUnsafePtr(
const QualType
T)
const final {
436 return RTC->isUnretained(
T);
441 bool isSafePtrType(
const QualType
type)
const final {
444 bool isSafeExpr(
const Expr *E)
const final {
448 bool isSafeDecl(
const Decl *D)
const final {
452 const char *ptrKind() const final {
return "unretained"; }
457void ento::registerUncountedLocalVarsChecker(
CheckerManager &Mgr) {
461bool ento::shouldRegisterUncountedLocalVarsChecker(
const CheckerManager &) {
465void ento::registerUncheckedLocalVarsChecker(
CheckerManager &Mgr) {
469bool ento::shouldRegisterUncheckedLocalVarsChecker(
const CheckerManager &) {
473void ento::registerUnretainedLocalVarsChecker(
CheckerManager &Mgr) {
477bool ento::shouldRegisterUnretainedLocalVarsChecker(
const CheckerManager &) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
llvm::MachO::Record Record
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.
static bool isAssignmentOp(Opcode Opc)
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.
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
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 }.
ASTContext & getASTContext() const LLVM_READONLY
SourceLocation getLocation() const
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
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.
bool isTrivial(const Decl *D) const
Represents a variable declaration or definition.
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
const SourceManager & getSourceManager()
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
bool isCocoaObjectRef(QualType T)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
bool isExprToGetCheckedPtrCapableMember(const clang::Expr *E)
bool isRefOrCheckedPtrType(const clang::QualType T)
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
bool isRetainPtrOrOSPtrType(const clang::QualType T)
bool tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj, std::function< bool(const clang::CXXRecordDecl *)> isSafePtr, std::function< bool(const clang::QualType)> isSafePtrType, std::function< bool(const clang::Decl *)> isSafeGlobalDecl, 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::optional< bool > isUnsafePtr(const QualType T, bool IsArcEnabled)
const FunctionProtoType * T
bool isSmartPtrClass(const std::string &Name)
bool isRefCounted(const CXXRecordDecl *R)
@ Type
The name was classified as a type.
bool isRetainPtrOrOSPtr(const std::string &Name)
std::optional< bool > isUncountedPtr(const QualType T)
bool isSafePtr(clang::CXXRecordDecl *Decl)
std::string safeGetName(const T *ASTNode)
bool isNullPtr(const clang::Expr *E)
bool isCheckedPtr(const std::string &Name)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
bool isConstOwnerPtrMemberExpr(const clang::Expr *E)
std::optional< bool > isUncheckedPtr(const QualType T)