diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/WebKit')
8 files changed, 77 insertions, 22 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index 66cfccb..419d263 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -26,6 +26,7 @@ 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) { while (E) { if (auto *DRE = dyn_cast<DeclRefExpr>(E)) { @@ -34,6 +35,8 @@ bool tryToFindPtrOrigin( auto IsImmortal = safeGetName(VD) == "NSApp"; if (VD->hasGlobalStorage() && (IsImmortal || QT.isConstQualified())) return callback(E, true); + if (VD->hasGlobalStorage() && isSafeGlobalDecl(VD)) + return callback(E, true); } } if (auto *tempExpr = dyn_cast<MaterializeTemporaryExpr>(E)) { @@ -71,9 +74,11 @@ bool tryToFindPtrOrigin( } if (auto *Expr = dyn_cast<ConditionalOperator>(E)) { return tryToFindPtrOrigin(Expr->getTrueExpr(), StopAtFirstRefCountedObj, - isSafePtr, isSafePtrType, callback) && + isSafePtr, isSafePtrType, isSafeGlobalDecl, + callback) && tryToFindPtrOrigin(Expr->getFalseExpr(), StopAtFirstRefCountedObj, - isSafePtr, isSafePtrType, callback); + isSafePtr, isSafePtrType, isSafeGlobalDecl, + callback); } if (auto *cast = dyn_cast<CastExpr>(E)) { if (StopAtFirstRefCountedObj) { @@ -93,7 +98,8 @@ bool tryToFindPtrOrigin( if (auto *call = dyn_cast<CallExpr>(E)) { if (auto *Callee = call->getCalleeDecl()) { if (Callee->hasAttr<CFReturnsRetainedAttr>() || - Callee->hasAttr<NSReturnsRetainedAttr>()) { + Callee->hasAttr<NSReturnsRetainedAttr>() || + Callee->hasAttr<NSReturnsAutoreleasedAttr>()) { return callback(E, true); } } @@ -158,7 +164,9 @@ bool tryToFindPtrOrigin( auto Name = safeGetName(callee); if (Name == "__builtin___CFStringMakeConstantString" || - Name == "NSClassFromString") + Name == "NSStringFromSelector" || Name == "NSSelectorFromString" || + Name == "NSStringFromClass" || Name == "NSClassFromString" || + Name == "NSStringFromProtocol" || Name == "NSProtocolFromString") return callback(E, true); } else if (auto *CalleeE = call->getCallee()) { if (auto *E = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) { @@ -176,7 +184,7 @@ bool tryToFindPtrOrigin( if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(RetType)) { if (auto *SubstType = Subst->desugar().getTypePtr()) { if (auto *RD = dyn_cast<RecordType>(SubstType)) { - if (auto *CXX = dyn_cast<CXXRecordDecl>(RD->getOriginalDecl())) + if (auto *CXX = dyn_cast<CXXRecordDecl>(RD->getDecl())) if (isSafePtr(CXX)) return callback(E, true); } @@ -196,6 +204,8 @@ bool tryToFindPtrOrigin( !Selector.getNumArgs()) return callback(E, true); } + if (auto *ObjCProtocol = dyn_cast<ObjCProtocolExpr>(E)) + return callback(ObjCProtocol, true); if (auto *ObjCDict = dyn_cast<ObjCDictionaryLiteral>(E)) return callback(ObjCDict, true); if (auto *ObjCArray = dyn_cast<ObjCArrayLiteral>(E)) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h index 3a009d6..9fff456 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h @@ -56,6 +56,7 @@ bool tryToFindPtrOrigin( const clang::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); /// For \p E referring to a ref-countable/-counted pointer/reference we return diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp index d8539ea..1d4e6dd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp @@ -263,18 +263,43 @@ public: void visitCallArg(const Expr *Arg, const ParmVarDecl *Param, const Decl *DeclWithIssue) const { auto *ArgExpr = Arg->IgnoreParenCasts(); - if (auto *InnerCE = dyn_cast<CallExpr>(Arg)) { - auto *InnerCallee = InnerCE->getDirectCallee(); - if (InnerCallee && InnerCallee->isInStdNamespace() && - safeGetName(InnerCallee) == "move" && InnerCE->getNumArgs() == 1) { - ArgExpr = InnerCE->getArg(0); - if (ArgExpr) - ArgExpr = ArgExpr->IgnoreParenCasts(); + while (ArgExpr) { + ArgExpr = ArgExpr->IgnoreParenCasts(); + if (auto *InnerCE = dyn_cast<CallExpr>(ArgExpr)) { + auto *InnerCallee = InnerCE->getDirectCallee(); + if (InnerCallee && InnerCallee->isInStdNamespace() && + safeGetName(InnerCallee) == "move" && InnerCE->getNumArgs() == 1) { + ArgExpr = InnerCE->getArg(0); + continue; + } + } + if (auto *UO = dyn_cast<UnaryOperator>(ArgExpr)) { + auto OpCode = UO->getOpcode(); + if (OpCode == UO_Deref || OpCode == UO_AddrOf) { + ArgExpr = UO->getSubExpr(); + continue; + } } + break; } + + if (auto *MemberCallExpr = dyn_cast<CXXMemberCallExpr>(ArgExpr)) { + if (isOwnerPtrType(MemberCallExpr->getObjectType())) + return; + } + + if (auto *OpCE = dyn_cast<CXXOperatorCallExpr>(ArgExpr)) { + auto *Method = dyn_cast_or_null<CXXMethodDecl>(OpCE->getDirectCallee()); + if (Method && isOwnerPtr(safeGetName(Method->getParent()))) { + if (OpCE->getOperator() == OO_Star && OpCE->getNumArgs() == 1) + return; + } + } + if (isNullPtr(ArgExpr) || isa<IntegerLiteral>(ArgExpr) || isa<CXXDefaultArgExpr>(ArgExpr)) return; + if (auto *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) { if (auto *ValDecl = DRE->getDecl()) { if (isa<ParmVarDecl>(ValDecl)) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index e5c74bb..d3d1f13 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -138,6 +138,11 @@ bool isCheckedPtr(const std::string &Name) { return Name == "CheckedPtr" || Name == "CheckedRef"; } +bool isOwnerPtr(const std::string &Name) { + return isRefType(Name) || isCheckedPtr(Name) || Name == "unique_ptr" || + Name == "UniqueRef" || Name == "LazyUniqueRef"; +} + bool isSmartPtrClass(const std::string &Name) { return isRefType(Name) || isCheckedPtr(Name) || isRetainPtrOrOSPtr(Name) || Name == "WeakPtr" || Name == "WeakPtrFactory" || @@ -206,10 +211,7 @@ bool isRetainPtrOrOSPtrType(const clang::QualType T) { } bool isOwnerPtrType(const clang::QualType T) { - return isPtrOfType(T, [](auto Name) { - return isRefType(Name) || isCheckedPtr(Name) || Name == "unique_ptr" || - Name == "UniqueRef" || Name == "LazyUniqueRef"; - }); + return isPtrOfType(T, [](auto Name) { return isOwnerPtr(Name); }); } std::optional<bool> isUncounted(const QualType T) { @@ -255,7 +257,7 @@ void RetainTypeChecker::visitTypedef(const TypedefDecl *TD) { return; } - for (auto *Redecl : RT->getOriginalDecl()->getMostRecentDecl()->redecls()) { + for (auto *Redecl : RT->getDecl()->getMostRecentDecl()->redecls()) { if (Redecl->getAttr<ObjCBridgeAttr>() || Redecl->getAttr<ObjCBridgeMutableAttr>()) { CFPointees.insert(RT); @@ -296,7 +298,7 @@ std::optional<bool> isUnretained(const QualType T, bool IsARCEnabled) { auto *Record = PointeeType->getAsStructureType(); if (!Record) return false; - auto *Decl = Record->getOriginalDecl(); + auto *Decl = Record->getDecl(); if (!Decl) return false; auto TypeName = Decl->getName(); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index 8300a6c..12e2e2d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -143,6 +143,10 @@ bool isCheckedPtr(const std::string &Name); /// \returns true if \p Name is RetainPtr or its variant, false if not. bool isRetainPtrOrOSPtr(const std::string &Name); +/// \returns true if \p Name is an owning smar pointer such as Ref, CheckedPtr, +/// and unique_ptr. +bool isOwnerPtr(const std::string &Name); + /// \returns true if \p Name is a smart pointer type name, false if not. bool isSmartPtrClass(const std::string &Name); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp index 9585ceb..791e709 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp @@ -29,12 +29,12 @@ namespace { class RawPtrRefCallArgsChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> { BugType Bug; - mutable BugReporter *BR; TrivialFunctionAnalysis TFA; EnsureFunctionAnalysis EFA; protected: + mutable BugReporter *BR; mutable std::optional<RetainTypeChecker> RTC; public: @@ -46,6 +46,7 @@ public: virtual bool isSafePtr(const CXXRecordDecl *Record) const = 0; virtual bool isSafePtrType(const QualType type) const = 0; virtual bool isSafeExpr(const Expr *) const { return false; } + virtual bool isSafeDecl(const Decl *) const { return false; } virtual const char *ptrKind() const = 0; void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, @@ -214,6 +215,7 @@ public: Arg, /*StopAtFirstRefCountedObj=*/true, [&](const clang::CXXRecordDecl *Record) { return isSafePtr(Record); }, [&](const clang::QualType T) { return isSafePtrType(T); }, + [&](const clang::Decl *D) { return isSafeDecl(D); }, [&](const clang::Expr *ArgOrigin, bool IsSafe) { if (IsSafe) return true; @@ -479,6 +481,11 @@ public: isa<ObjCMessageExpr>(E); } + bool isSafeDecl(const Decl *D) const final { + // Treat NS/CF globals in system header as immortal. + return BR->getSourceManager().isInSystemHeader(D->getLocation()); + } + const char *ptrKind() const final { return "unretained"; } }; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp index dd9701f..c13df479 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp @@ -166,10 +166,10 @@ bool isGuardedScopeEmbeddedInGuardianScope(const VarDecl *Guarded, class RawPtrRefLocalVarsChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> { BugType Bug; - mutable BugReporter *BR; EnsureFunctionAnalysis EFA; protected: + mutable BugReporter *BR; mutable std::optional<RetainTypeChecker> RTC; public: @@ -180,6 +180,7 @@ public: virtual bool isSafePtr(const CXXRecordDecl *) const = 0; virtual bool isSafePtrType(const QualType) const = 0; virtual bool isSafeExpr(const Expr *) const { return false; } + virtual bool isSafeDecl(const Decl *) const { return false; } virtual const char *ptrKind() const = 0; void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, @@ -288,6 +289,7 @@ public: return isSafePtr(Record); }, [&](const clang::QualType Type) { return isSafePtrType(Type); }, + [&](const clang::Decl *D) { return isSafeDecl(D); }, [&](const clang::Expr *InitArgOrigin, bool IsSafe) { if (!InitArgOrigin || IsSafe) return true; @@ -443,6 +445,10 @@ public: return ento::cocoa::isCocoaObjectRef(E->getType()) && isa<ObjCMessageExpr>(E); } + bool isSafeDecl(const Decl *D) const final { + // Treat NS/CF globals in system header as immortal. + return BR->getSourceManager().isInSystemHeader(D->getLocation()); + } const char *ptrKind() const final { return "unretained"; } }; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp index 6f3a280..c6421f8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp @@ -121,13 +121,13 @@ public: return true; } } else if (auto *RD = dyn_cast<RecordType>(PointeeType)) { - if (declaresSameEntity(RD->getOriginalDecl(), ClassDecl)) + if (declaresSameEntity(RD->getDecl(), ClassDecl)) return true; } else if (auto *ST = dyn_cast<SubstTemplateTypeParmType>(PointeeType)) { auto Type = ST->getReplacementType(); if (auto *RD = dyn_cast<RecordType>(Type)) { - if (declaresSameEntity(RD->getOriginalDecl(), ClassDecl)) + if (declaresSameEntity(RD->getDecl(), ClassDecl)) return true; } } |