diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index f087fc8fa19fd..30d4dee13b797 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -231,6 +231,26 @@ bool isConstOwnerPtrMemberExpr(const clang::Expr *E) { return isOwnerPtrType(T) && T.isConstQualified(); } +bool isExprToGetCheckedPtrCapableMember(const clang::Expr *E) { + auto *ME = dyn_cast(E); + if (!ME) + return false; + auto *Base = ME->getBase(); + if (!Base) + return false; + if (!isa(Base->IgnoreParenCasts())) + return false; + auto *D = ME->getMemberDecl(); + if (!D) + return false; + auto T = D->getType(); + auto *CXXRD = T->getAsCXXRecordDecl(); + if (!CXXRD) + return false; + auto result = isCheckedPtrCapable(CXXRD); + return result && *result; +} + class EnsureFunctionVisitor : public ConstStmtVisitor { public: diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h index e2cc7b976adfc..8302bbe3084c2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h @@ -69,6 +69,10 @@ bool isASafeCallArg(const clang::Expr *E); /// \returns true if E is a MemberExpr accessing a const smart pointer type. bool isConstOwnerPtrMemberExpr(const clang::Expr *E); +/// \returns true if E is a MemberExpr accessing a member variable which +/// supports CheckedPtr. +bool isExprToGetCheckedPtrCapableMember(const clang::Expr *E); + /// \returns true if E is a CXXMemberCallExpr which returns a const smart /// pointer type. class EnsureFunctionAnalysis { diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp index 78675e55cf0ba..6bc39ab565041 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp @@ -443,6 +443,10 @@ class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker { return isRefOrCheckedPtrType(type); } + bool isSafeExpr(const Expr *E) const final { + return isExprToGetCheckedPtrCapableMember(E); + } + const char *ptrKind() const final { return "unchecked"; } }; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp index 4fb47703e3984..7cd86a682c0a9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp @@ -417,6 +417,9 @@ class UncheckedLocalVarsChecker final : public RawPtrRefLocalVarsChecker { bool isSafePtrType(const QualType type) const final { return isRefOrCheckedPtrType(type); } + bool isSafeExpr(const Expr *E) const final { + return isExprToGetCheckedPtrCapableMember(E); + } const char *ptrKind() const final { return "unchecked"; } }; diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp index e24b04dcd3cf9..b6cb70ec0257e 100644 --- a/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp +++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp @@ -32,6 +32,26 @@ static void baz() { } // namespace call_args_checked +namespace call_args_member { + +void consume(CheckedObj&); + +struct WrapperObj { + CheckedObj checked; + CheckedObj& checkedRef; + void foo() { + consume(checked); + consume(checkedRef); + // expected-warning@-1{{Call argument is unchecked and unsafe [alpha.webkit.UncheckedCallArgsChecker]}} + } + void bar(WrapperObj& other) { + consume(other.checked); + // expected-warning@-1{{Call argument is unchecked and unsafe [alpha.webkit.UncheckedCallArgsChecker]}} + } +}; + +} // namespace call_args_checked + namespace call_args_default { void someFunction(RefCountableAndCheckable* = makeObj()); diff --git a/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp index 3bc75230fcf82..2984f8ba4eefa 100644 --- a/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp +++ b/clang/test/Analysis/Checkers/WebKit/unchecked-local-vars.cpp @@ -290,6 +290,28 @@ void foo() { } // namespace local_assignment_to_global +namespace member_var { + + struct WrapperObj { + CheckedObj checked; + CheckedObj& checkedRef; + void foo() { + auto *a = &checked; + a->method(); + auto *b = &checkedRef; + // expected-warning@-1{{Local variable 'b' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}} + b->method(); + } + + void bar(WrapperObj& wrapper) { + CheckedObj* ptr = &wrapper.checked; + // expected-warning@-1{{Local variable 'ptr' is unchecked and unsafe [alpha.webkit.UncheckedLocalVarsChecker]}} + ptr->method(); + } + }; + +} + namespace local_refcountable_checkable_object { RefCountableAndCheckable* provide_obj();