-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Introduce a new WebKit checker for a unchecked call arguments (#113708) #114522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Ryosuke Niwa (rniwa) ChangesThis PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a function argument which is a raw reference or a raw pointer to a CheckedPtr capable object. Patch is 20.11 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/114522.diff 8 Files Affected:
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 86d62b58cac0fb..bc172c7d2fe348 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1760,6 +1760,10 @@ def UncountedCallArgsChecker : Checker<"UncountedCallArgsChecker">,
HelpText<"Check uncounted call arguments.">,
Documentation<HasDocumentation>;
+def UncheckedCallArgsChecker : Checker<"UncheckedCallArgsChecker">,
+ HelpText<"Check unchecked call arguments.">,
+ Documentation<NotDocumented>;
+
def UncountedLocalVarsChecker : Checker<"UncountedLocalVarsChecker">,
HelpText<"Check uncounted local variables.">,
Documentation<HasDocumentation>;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index c6e5afdc42424c..f40318f46dea1a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -134,7 +134,7 @@ add_clang_library(clangStaticAnalyzerCheckers
WebKit/ASTUtils.cpp
WebKit/PtrTypesSemantics.cpp
WebKit/RefCntblBaseVirtualDtorChecker.cpp
- WebKit/UncountedCallArgsChecker.cpp
+ WebKit/RawPtrRefCallArgsChecker.cpp
WebKit/UncountedLambdaCapturesChecker.cpp
WebKit/RawPtrRefLocalVarsChecker.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 46819d5ca12058..2c80bd86375431 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -173,6 +173,16 @@ std::optional<bool> isUncounted(const QualType T) {
return isUncounted(T->getAsCXXRecordDecl());
}
+std::optional<bool> isUnchecked(const QualType T) {
+ if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
+ if (auto *Decl = Subst->getAssociatedDecl()) {
+ if (isCheckedPtr(safeGetName(Decl)))
+ return false;
+ }
+ }
+ return isUnchecked(T->getAsCXXRecordDecl());
+}
+
std::optional<bool> isUncounted(const CXXRecordDecl* Class)
{
// Keep isRefCounted first as it's cheaper.
@@ -187,7 +197,7 @@ std::optional<bool> isUncounted(const CXXRecordDecl* Class)
}
std::optional<bool> isUnchecked(const CXXRecordDecl *Class) {
- if (isCheckedPtr(Class))
+ if (!Class || isCheckedPtr(Class))
return false; // Cheaper than below
return isCheckedPtrCapable(Class);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 30bdaed706bb53..54c4872ad57d8c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -55,10 +55,18 @@ bool isCheckedPtr(const clang::CXXRecordDecl *Class);
/// not, std::nullopt if inconclusive.
std::optional<bool> isUncounted(const clang::QualType T);
+/// \returns true if \p Class is CheckedPtr capable AND not checked, false if
+/// not, std::nullopt if inconclusive.
+std::optional<bool> isUnchecked(const clang::QualType T);
+
/// \returns true if \p Class is ref-countable AND not ref-counted, false if
/// not, std::nullopt if inconclusive.
std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
+/// \returns true if \p Class is CheckedPtr capable AND not checked, false if
+/// not, std::nullopt if inconclusive.
+std::optional<bool> isUnchecked(const clang::CXXRecordDecl* Class);
+
/// \returns true if \p T is either a raw pointer or reference to an uncounted
/// class, false if not, std::nullopt if inconclusive.
std::optional<bool> isUncountedPtr(const clang::QualType T);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
similarity index 82%
rename from clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
rename to clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
index 1a5a7309a54f16..f1fbe61c421f88 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
@@ -1,4 +1,4 @@
-//=======- UncountedCallArgsChecker.cpp --------------------------*- C++ -*-==//
+//=======- RawPtrRefCallArgsChecker.cpp --------------------------*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -27,16 +27,20 @@ using namespace ento;
namespace {
-class UncountedCallArgsChecker
+class RawPtrRefCallArgsChecker
: public Checker<check::ASTDecl<TranslationUnitDecl>> {
- BugType Bug{this,
- "Uncounted call argument for a raw pointer/reference parameter",
- "WebKit coding guidelines"};
+ BugType Bug;
mutable BugReporter *BR;
TrivialFunctionAnalysis TFA;
public:
+ RawPtrRefCallArgsChecker(const char* description)
+ : Bug(this, description, "WebKit coding guidelines") {}
+
+ virtual std::optional<bool> isUnsafeType(QualType) const = 0;
+ virtual std::optional<bool> isUnsafePtr(QualType) const = 0;
+ virtual const char *ptrKind() const = 0;
void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
BugReporter &BRArg) const {
@@ -48,10 +52,10 @@ class UncountedCallArgsChecker
struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
using Base = RecursiveASTVisitor<LocalVisitor>;
- const UncountedCallArgsChecker *Checker;
+ const RawPtrRefCallArgsChecker *Checker;
Decl *DeclWithIssue{nullptr};
- explicit LocalVisitor(const UncountedCallArgsChecker *Checker)
+ explicit LocalVisitor(const RawPtrRefCallArgsChecker *Checker)
: Checker(Checker) {
assert(Checker);
}
@@ -101,8 +105,8 @@ class UncountedCallArgsChecker
}
auto *E = MemberCallExpr->getImplicitObjectArgument();
QualType ArgType = MemberCallExpr->getObjectType().getCanonicalType();
- std::optional<bool> IsUncounted = isUncounted(ArgType);
- if (IsUncounted && *IsUncounted && !isPtrOriginSafe(E))
+ std::optional<bool> IsUnsafe = isUnsafeType(ArgType);
+ if (IsUnsafe && *IsUnsafe && !isPtrOriginSafe(E))
reportBugOnThis(E, D);
}
@@ -118,7 +122,7 @@ class UncountedCallArgsChecker
QualType ArgType = (*P)->getType().getCanonicalType();
// FIXME: more complex types (arrays, references to raw pointers, etc)
- std::optional<bool> IsUncounted = isUncountedPtr(ArgType);
+ std::optional<bool> IsUncounted = isUnsafePtr(ArgType);
if (!IsUncounted || !(*IsUncounted))
continue;
@@ -264,7 +268,7 @@ class UncountedCallArgsChecker
Os << " for parameter ";
printQuotedQualifiedName(Os, Param);
}
- Os << " is uncounted and unsafe.";
+ Os << " is " << ptrKind() << " and unsafe.";
const SourceLocation SrcLocToReport =
isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg()->getExprLoc()
@@ -282,15 +286,53 @@ class UncountedCallArgsChecker
const SourceLocation SrcLocToReport = CallArg->getSourceRange().getBegin();
+ SmallString<100> Buf;
+ llvm::raw_svector_ostream Os(Buf);
+ Os << "Call argument for 'this' parameter is " << ptrKind();
+ Os << " and unsafe.";
+
PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
- auto Report = std::make_unique<BasicBugReport>(
- Bug, "Call argument for 'this' parameter is uncounted and unsafe.",
- BSLoc);
+ auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
Report->addRange(CallArg->getSourceRange());
Report->setDeclWithIssue(DeclWithIssue);
BR->emitReport(std::move(Report));
}
};
+
+class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
+public:
+ UncountedCallArgsChecker()
+ : RawPtrRefCallArgsChecker("Uncounted call argument for a raw "
+ "pointer/reference parameter") {}
+
+ std::optional<bool> isUnsafeType(QualType QT) const final {
+ return isUncounted(QT);
+ }
+
+ std::optional<bool> isUnsafePtr(QualType QT) const final {
+ return isUncountedPtr(QT);
+ }
+
+ const char *ptrKind() const final { return "uncounted"; }
+};
+
+class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
+public:
+ UncheckedCallArgsChecker()
+ : RawPtrRefCallArgsChecker("Unchecked call argument for a raw "
+ "pointer/reference parameter") {}
+
+ std::optional<bool> isUnsafeType(QualType QT) const final {
+ return isUnchecked(QT);
+ }
+
+ std::optional<bool> isUnsafePtr(QualType QT) const final {
+ return isUncheckedPtr(QT);
+ }
+
+ const char *ptrKind() const final { return "unchecked"; }
+};
+
} // namespace
void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) {
@@ -300,3 +342,11 @@ void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) {
bool ento::shouldRegisterUncountedCallArgsChecker(const CheckerManager &) {
return true;
}
+
+void ento::registerUncheckedCallArgsChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<UncheckedCallArgsChecker>();
+}
+
+bool ento::shouldRegisterUncheckedCallArgsChecker(const CheckerManager &) {
+ return true;
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp
new file mode 100644
index 00000000000000..34ff0c70e230ea
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp
@@ -0,0 +1,367 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedCallArgsChecker -verify %s
+
+#include "mock-types.h"
+
+CheckedObj* provide();
+void consume_refcntbl(CheckedObj*);
+void some_function();
+
+namespace simple {
+ void foo() {
+ consume_refcntbl(provide());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+ }
+
+ // Test that the checker works with [[clang::suppress]].
+ void foo_suppressed() {
+ [[clang::suppress]]
+ consume_refcntbl(provide()); // no-warning
+ }
+}
+
+namespace multi_arg {
+ void consume_refcntbl(int, CheckedObj* foo, bool);
+ void foo() {
+ consume_refcntbl(42, provide(), true);
+ // expected-warning@-1{{Call argument for parameter 'foo' is unchecked and unsafe}}
+ }
+}
+
+namespace ref_counted {
+ CheckedRef<CheckedObj> provide_ref_counted() { return CheckedRef<CheckedObj>{}; }
+ void consume_ref_counted(CheckedRef<CheckedObj>) {}
+
+ void foo() {
+ consume_refcntbl(provide_ref_counted().ptr());
+ // no warning
+ }
+}
+
+namespace methods {
+ struct Consumer {
+ void consume_ptr(CheckedObj* ptr);
+ void consume_ref(const CheckedObj& ref);
+ };
+
+ void foo() {
+ Consumer c;
+
+ c.consume_ptr(provide());
+ // expected-warning@-1{{Call argument for parameter 'ptr' is unchecked and unsafe}}
+ c.consume_ref(*provide());
+ // expected-warning@-1{{Call argument for parameter 'ref' is unchecked and unsafe}}
+ }
+
+ void foo2() {
+ struct Consumer {
+ void consume(CheckedObj*) { some_function(); }
+ void whatever() {
+ consume(provide());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+ }
+ };
+ }
+
+ void foo3() {
+ struct Consumer {
+ void consume(CheckedObj*) { some_function(); }
+ void whatever() {
+ this->consume(provide());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+ }
+ };
+ }
+}
+
+namespace casts {
+ CheckedObj* downcast(CheckedObj*);
+
+ void foo() {
+ consume_refcntbl(provide());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(static_cast<CheckedObj*>(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(dynamic_cast<CheckedObj*>(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(const_cast<CheckedObj*>(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(reinterpret_cast<CheckedObj*>(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(downcast(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(
+ static_cast<CheckedObj*>(
+ downcast(
+ static_cast<CheckedObj*>(
+ provide()
+ )
+ )
+ )
+ );
+ // expected-warning@-8{{Call argument is unchecked and unsafe}}
+ }
+}
+
+namespace null_ptr {
+ void foo_ref() {
+ consume_refcntbl(nullptr);
+ consume_refcntbl(0);
+ }
+}
+
+namespace ref_counted_lookalike {
+ struct Decoy {
+ CheckedObj* get() { return nullptr; }
+ };
+
+ void foo() {
+ Decoy D;
+
+ consume_refcntbl(D.get());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+ }
+}
+
+namespace Ref_to_reference_conversion_operator {
+ template<typename T> struct Ref {
+ Ref() = default;
+ Ref(T*) { }
+ T* get() { return nullptr; }
+ operator T& () { return t; }
+ T t;
+ };
+
+ void consume_ref(CheckedObj&) {}
+
+ void foo() {
+ CheckedRef<CheckedObj> bar;
+ consume_ref(bar);
+ }
+}
+
+namespace param_formarding_function {
+ void consume_ref_countable_ref(CheckedObj&);
+ void consume_ref_countable_ptr(CheckedObj*);
+
+ namespace ptr {
+ void foo(CheckedObj* param) {
+ consume_ref_countable_ptr(param);
+ }
+ }
+
+ namespace ref {
+ void foo(CheckedObj& param) {
+ consume_ref_countable_ref(param);
+ }
+ }
+
+ namespace ref_deref_operators {
+ void foo_ref(CheckedObj& param) {
+ consume_ref_countable_ptr(¶m);
+ }
+
+ void foo_ptr(CheckedObj* param) {
+ consume_ref_countable_ref(*param);
+ }
+ }
+
+ namespace casts {
+
+ CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+ template<class T>
+ T* bitwise_cast(T*) { return nullptr; }
+
+ void foo(CheckedObj* param) {
+ consume_ref_countable_ptr(downcast(param));
+ consume_ref_countable_ptr(bitwise_cast(param));
+ }
+ }
+}
+
+namespace param_formarding_lambda {
+ auto consume_ref_countable_ref = [](CheckedObj&) { some_function(); };
+ auto consume_ref_countable_ptr = [](CheckedObj*) { some_function(); };
+
+ namespace ptr {
+ void foo(CheckedObj* param) {
+ consume_ref_countable_ptr(param);
+ }
+ }
+
+ namespace ref {
+ void foo(CheckedObj& param) {
+ consume_ref_countable_ref(param);
+ }
+ }
+
+ namespace ref_deref_operators {
+ void foo_ref(CheckedObj& param) {
+ consume_ref_countable_ptr(¶m);
+ }
+
+ void foo_ptr(CheckedObj* param) {
+ consume_ref_countable_ref(*param);
+ }
+ }
+
+ namespace casts {
+
+ CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+ template<class T>
+ T* bitwise_cast(T*) { return nullptr; }
+
+ void foo(CheckedObj* param) {
+ consume_ref_countable_ptr(downcast(param));
+ consume_ref_countable_ptr(bitwise_cast(param));
+ }
+ }
+}
+
+namespace param_forwarding_method {
+ struct methodclass {
+ void consume_ref_countable_ref(CheckedObj&) {};
+ static void consume_ref_countable_ptr(CheckedObj*) {};
+ };
+
+ namespace ptr {
+ void foo(CheckedObj* param) {
+ methodclass::consume_ref_countable_ptr(param);
+ }
+ }
+
+ namespace ref {
+ void foo(CheckedObj& param) {
+ methodclass mc;
+ mc.consume_ref_countable_ref(param);
+ }
+ }
+
+ namespace ref_deref_operators {
+ void foo_ref(CheckedObj& param) {
+ methodclass::consume_ref_countable_ptr(¶m);
+ }
+
+ void foo_ptr(CheckedObj* param) {
+ methodclass mc;
+ mc.consume_ref_countable_ref(*param);
+ }
+ }
+
+ namespace casts {
+
+ CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+ template<class T>
+ T* bitwise_cast(T*) { return nullptr; }
+
+ void foo(CheckedObj* param) {
+ methodclass::consume_ref_countable_ptr(downcast(param));
+ methodclass::consume_ref_countable_ptr(bitwise_cast(param));
+ }
+ }
+}
+
+namespace downcast {
+ void consume_ref_countable(CheckedObj*) {}
+ CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+ void foo() {
+ CheckedPtr<CheckedObj> bar;
+ consume_ref_countable( downcast(bar.get()) );
+ }
+}
+
+namespace string_impl {
+ struct String {
+ CheckedObj* impl() { return nullptr; }
+ };
+
+ struct AtomString {
+ CheckedObj rc;
+ CheckedObj& impl() { return rc; }
+ };
+
+ void consume_ptr(CheckedObj*) {}
+ void consume_ref(CheckedObj&) {}
+
+ namespace simple {
+ void foo() {
+ String s;
+ AtomString as;
+ consume_ptr(s.impl());
+ consume_ref(as.impl());
+ }
+ }
+}
+
+namespace default_arg {
+ CheckedObj* global;
+
+ void function_with_default_arg(CheckedObj* param = global);
+ // expected-warning@-1{{Call argument for parameter 'param' is unchecked and unsafe}}
+
+ void foo() {
+ function_with_default_arg();
+ }
+}
+
+namespace cxx_member_func {
+ CheckedRef<CheckedObj> provideProtected();
+ void foo() {
+ provide()->trivial();
+ provide()->method();
+ // expected-warning@-1{{Call argument for 'this' parameter is unchecked and unsafe}}
+ provideProtected()->method();
+ (provideProtected())->method();
+ };
+}
+
+namespace cxx_member_operator_call {
+ // The hidden this-pointer argument without a corresponding parameter caused couple bugs in parameter <-> argument attribution.
+ struct Foo {
+ Foo& operator+(CheckedObj* bad);
+ friend Foo& operator-(Foo& lhs, CheckedObj* bad);
+ void operator()(CheckedObj* bad);
+ };
+
+ CheckedObj* global;
+
+ void foo() {
+ Foo f;
+ f + global;
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ f - global;
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ f(global);
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ }
+}
+
+namespace call_with_ptr_on_ref {
+ CheckedRef<CheckedObj> provideProtected();
+ void bar(CheckedObj* bad);
+ bool baz();
+ void foo(bool v) {
+ bar(v ? nullptr : provideProtected().ptr());
+ bar(baz() ? provideProtected().ptr() : nullptr);
+ bar(v ? provide() : provideProtected().ptr());
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ bar(v ? provideProtected().ptr() : provide());
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ }
+}
+
+namespace call_with_explicit_temporary_obj {
+ void foo() {
+ CheckedRef { *provide() }->method();
+ CheckedPtr { provide() }->method();
+ }
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp
new file mode 100644
index 00000000000000..33f7f8272a2560
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+class Checkable {
+public:
+ void ref() const;
+ void deref() const;
+};
+
+class Object {
+public:
+ void ref() const;
+ void deref() const;
+ void someFunction(Checkable&);
+};
+
+RefPtr<Object> object();
+RefPtr<Checkable> protectedTargetObject();
+
+void testFunction() {
+ if (RefPtr obj = object())
+ obj->someFunction(*protectedTargetObject());
+}
diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
index 6a4c92390d773b..8579141aa7f99c 100644
--- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
+++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
@@ -142,7 +142,7 @@ static_library("Checkers") {
"WebKit/PtrTypesSemantics.cpp",
"WebKit/RawPtrRefMemberChecker.cpp",
"WebKit/RefCntblBaseVirtualDtorChecker.cpp",
- "WebKit/UncountedCallArgsChecker.cpp",
+ "WebKit/RawPtrRefCallArgsChecker.cpp",
"WebKit/Unco...
[truncated]
|
@llvm/pr-subscribers-clang-static-analyzer-1 Author: Ryosuke Niwa (rniwa) ChangesThis PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a function argument which is a raw reference or a raw pointer to a CheckedPtr capable object. Patch is 20.11 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/114522.diff 8 Files Affected:
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 86d62b58cac0fb..bc172c7d2fe348 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1760,6 +1760,10 @@ def UncountedCallArgsChecker : Checker<"UncountedCallArgsChecker">,
HelpText<"Check uncounted call arguments.">,
Documentation<HasDocumentation>;
+def UncheckedCallArgsChecker : Checker<"UncheckedCallArgsChecker">,
+ HelpText<"Check unchecked call arguments.">,
+ Documentation<NotDocumented>;
+
def UncountedLocalVarsChecker : Checker<"UncountedLocalVarsChecker">,
HelpText<"Check uncounted local variables.">,
Documentation<HasDocumentation>;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index c6e5afdc42424c..f40318f46dea1a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -134,7 +134,7 @@ add_clang_library(clangStaticAnalyzerCheckers
WebKit/ASTUtils.cpp
WebKit/PtrTypesSemantics.cpp
WebKit/RefCntblBaseVirtualDtorChecker.cpp
- WebKit/UncountedCallArgsChecker.cpp
+ WebKit/RawPtrRefCallArgsChecker.cpp
WebKit/UncountedLambdaCapturesChecker.cpp
WebKit/RawPtrRefLocalVarsChecker.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 46819d5ca12058..2c80bd86375431 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -173,6 +173,16 @@ std::optional<bool> isUncounted(const QualType T) {
return isUncounted(T->getAsCXXRecordDecl());
}
+std::optional<bool> isUnchecked(const QualType T) {
+ if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
+ if (auto *Decl = Subst->getAssociatedDecl()) {
+ if (isCheckedPtr(safeGetName(Decl)))
+ return false;
+ }
+ }
+ return isUnchecked(T->getAsCXXRecordDecl());
+}
+
std::optional<bool> isUncounted(const CXXRecordDecl* Class)
{
// Keep isRefCounted first as it's cheaper.
@@ -187,7 +197,7 @@ std::optional<bool> isUncounted(const CXXRecordDecl* Class)
}
std::optional<bool> isUnchecked(const CXXRecordDecl *Class) {
- if (isCheckedPtr(Class))
+ if (!Class || isCheckedPtr(Class))
return false; // Cheaper than below
return isCheckedPtrCapable(Class);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 30bdaed706bb53..54c4872ad57d8c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -55,10 +55,18 @@ bool isCheckedPtr(const clang::CXXRecordDecl *Class);
/// not, std::nullopt if inconclusive.
std::optional<bool> isUncounted(const clang::QualType T);
+/// \returns true if \p Class is CheckedPtr capable AND not checked, false if
+/// not, std::nullopt if inconclusive.
+std::optional<bool> isUnchecked(const clang::QualType T);
+
/// \returns true if \p Class is ref-countable AND not ref-counted, false if
/// not, std::nullopt if inconclusive.
std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
+/// \returns true if \p Class is CheckedPtr capable AND not checked, false if
+/// not, std::nullopt if inconclusive.
+std::optional<bool> isUnchecked(const clang::CXXRecordDecl* Class);
+
/// \returns true if \p T is either a raw pointer or reference to an uncounted
/// class, false if not, std::nullopt if inconclusive.
std::optional<bool> isUncountedPtr(const clang::QualType T);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
similarity index 82%
rename from clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
rename to clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
index 1a5a7309a54f16..f1fbe61c421f88 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
@@ -1,4 +1,4 @@
-//=======- UncountedCallArgsChecker.cpp --------------------------*- C++ -*-==//
+//=======- RawPtrRefCallArgsChecker.cpp --------------------------*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -27,16 +27,20 @@ using namespace ento;
namespace {
-class UncountedCallArgsChecker
+class RawPtrRefCallArgsChecker
: public Checker<check::ASTDecl<TranslationUnitDecl>> {
- BugType Bug{this,
- "Uncounted call argument for a raw pointer/reference parameter",
- "WebKit coding guidelines"};
+ BugType Bug;
mutable BugReporter *BR;
TrivialFunctionAnalysis TFA;
public:
+ RawPtrRefCallArgsChecker(const char* description)
+ : Bug(this, description, "WebKit coding guidelines") {}
+
+ virtual std::optional<bool> isUnsafeType(QualType) const = 0;
+ virtual std::optional<bool> isUnsafePtr(QualType) const = 0;
+ virtual const char *ptrKind() const = 0;
void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
BugReporter &BRArg) const {
@@ -48,10 +52,10 @@ class UncountedCallArgsChecker
struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
using Base = RecursiveASTVisitor<LocalVisitor>;
- const UncountedCallArgsChecker *Checker;
+ const RawPtrRefCallArgsChecker *Checker;
Decl *DeclWithIssue{nullptr};
- explicit LocalVisitor(const UncountedCallArgsChecker *Checker)
+ explicit LocalVisitor(const RawPtrRefCallArgsChecker *Checker)
: Checker(Checker) {
assert(Checker);
}
@@ -101,8 +105,8 @@ class UncountedCallArgsChecker
}
auto *E = MemberCallExpr->getImplicitObjectArgument();
QualType ArgType = MemberCallExpr->getObjectType().getCanonicalType();
- std::optional<bool> IsUncounted = isUncounted(ArgType);
- if (IsUncounted && *IsUncounted && !isPtrOriginSafe(E))
+ std::optional<bool> IsUnsafe = isUnsafeType(ArgType);
+ if (IsUnsafe && *IsUnsafe && !isPtrOriginSafe(E))
reportBugOnThis(E, D);
}
@@ -118,7 +122,7 @@ class UncountedCallArgsChecker
QualType ArgType = (*P)->getType().getCanonicalType();
// FIXME: more complex types (arrays, references to raw pointers, etc)
- std::optional<bool> IsUncounted = isUncountedPtr(ArgType);
+ std::optional<bool> IsUncounted = isUnsafePtr(ArgType);
if (!IsUncounted || !(*IsUncounted))
continue;
@@ -264,7 +268,7 @@ class UncountedCallArgsChecker
Os << " for parameter ";
printQuotedQualifiedName(Os, Param);
}
- Os << " is uncounted and unsafe.";
+ Os << " is " << ptrKind() << " and unsafe.";
const SourceLocation SrcLocToReport =
isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg()->getExprLoc()
@@ -282,15 +286,53 @@ class UncountedCallArgsChecker
const SourceLocation SrcLocToReport = CallArg->getSourceRange().getBegin();
+ SmallString<100> Buf;
+ llvm::raw_svector_ostream Os(Buf);
+ Os << "Call argument for 'this' parameter is " << ptrKind();
+ Os << " and unsafe.";
+
PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
- auto Report = std::make_unique<BasicBugReport>(
- Bug, "Call argument for 'this' parameter is uncounted and unsafe.",
- BSLoc);
+ auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
Report->addRange(CallArg->getSourceRange());
Report->setDeclWithIssue(DeclWithIssue);
BR->emitReport(std::move(Report));
}
};
+
+class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker {
+public:
+ UncountedCallArgsChecker()
+ : RawPtrRefCallArgsChecker("Uncounted call argument for a raw "
+ "pointer/reference parameter") {}
+
+ std::optional<bool> isUnsafeType(QualType QT) const final {
+ return isUncounted(QT);
+ }
+
+ std::optional<bool> isUnsafePtr(QualType QT) const final {
+ return isUncountedPtr(QT);
+ }
+
+ const char *ptrKind() const final { return "uncounted"; }
+};
+
+class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker {
+public:
+ UncheckedCallArgsChecker()
+ : RawPtrRefCallArgsChecker("Unchecked call argument for a raw "
+ "pointer/reference parameter") {}
+
+ std::optional<bool> isUnsafeType(QualType QT) const final {
+ return isUnchecked(QT);
+ }
+
+ std::optional<bool> isUnsafePtr(QualType QT) const final {
+ return isUncheckedPtr(QT);
+ }
+
+ const char *ptrKind() const final { return "unchecked"; }
+};
+
} // namespace
void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) {
@@ -300,3 +342,11 @@ void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) {
bool ento::shouldRegisterUncountedCallArgsChecker(const CheckerManager &) {
return true;
}
+
+void ento::registerUncheckedCallArgsChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<UncheckedCallArgsChecker>();
+}
+
+bool ento::shouldRegisterUncheckedCallArgsChecker(const CheckerManager &) {
+ return true;
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp
new file mode 100644
index 00000000000000..34ff0c70e230ea
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-ptr.cpp
@@ -0,0 +1,367 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedCallArgsChecker -verify %s
+
+#include "mock-types.h"
+
+CheckedObj* provide();
+void consume_refcntbl(CheckedObj*);
+void some_function();
+
+namespace simple {
+ void foo() {
+ consume_refcntbl(provide());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+ }
+
+ // Test that the checker works with [[clang::suppress]].
+ void foo_suppressed() {
+ [[clang::suppress]]
+ consume_refcntbl(provide()); // no-warning
+ }
+}
+
+namespace multi_arg {
+ void consume_refcntbl(int, CheckedObj* foo, bool);
+ void foo() {
+ consume_refcntbl(42, provide(), true);
+ // expected-warning@-1{{Call argument for parameter 'foo' is unchecked and unsafe}}
+ }
+}
+
+namespace ref_counted {
+ CheckedRef<CheckedObj> provide_ref_counted() { return CheckedRef<CheckedObj>{}; }
+ void consume_ref_counted(CheckedRef<CheckedObj>) {}
+
+ void foo() {
+ consume_refcntbl(provide_ref_counted().ptr());
+ // no warning
+ }
+}
+
+namespace methods {
+ struct Consumer {
+ void consume_ptr(CheckedObj* ptr);
+ void consume_ref(const CheckedObj& ref);
+ };
+
+ void foo() {
+ Consumer c;
+
+ c.consume_ptr(provide());
+ // expected-warning@-1{{Call argument for parameter 'ptr' is unchecked and unsafe}}
+ c.consume_ref(*provide());
+ // expected-warning@-1{{Call argument for parameter 'ref' is unchecked and unsafe}}
+ }
+
+ void foo2() {
+ struct Consumer {
+ void consume(CheckedObj*) { some_function(); }
+ void whatever() {
+ consume(provide());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+ }
+ };
+ }
+
+ void foo3() {
+ struct Consumer {
+ void consume(CheckedObj*) { some_function(); }
+ void whatever() {
+ this->consume(provide());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+ }
+ };
+ }
+}
+
+namespace casts {
+ CheckedObj* downcast(CheckedObj*);
+
+ void foo() {
+ consume_refcntbl(provide());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(static_cast<CheckedObj*>(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(dynamic_cast<CheckedObj*>(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(const_cast<CheckedObj*>(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(reinterpret_cast<CheckedObj*>(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(downcast(provide()));
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+
+ consume_refcntbl(
+ static_cast<CheckedObj*>(
+ downcast(
+ static_cast<CheckedObj*>(
+ provide()
+ )
+ )
+ )
+ );
+ // expected-warning@-8{{Call argument is unchecked and unsafe}}
+ }
+}
+
+namespace null_ptr {
+ void foo_ref() {
+ consume_refcntbl(nullptr);
+ consume_refcntbl(0);
+ }
+}
+
+namespace ref_counted_lookalike {
+ struct Decoy {
+ CheckedObj* get() { return nullptr; }
+ };
+
+ void foo() {
+ Decoy D;
+
+ consume_refcntbl(D.get());
+ // expected-warning@-1{{Call argument is unchecked and unsafe}}
+ }
+}
+
+namespace Ref_to_reference_conversion_operator {
+ template<typename T> struct Ref {
+ Ref() = default;
+ Ref(T*) { }
+ T* get() { return nullptr; }
+ operator T& () { return t; }
+ T t;
+ };
+
+ void consume_ref(CheckedObj&) {}
+
+ void foo() {
+ CheckedRef<CheckedObj> bar;
+ consume_ref(bar);
+ }
+}
+
+namespace param_formarding_function {
+ void consume_ref_countable_ref(CheckedObj&);
+ void consume_ref_countable_ptr(CheckedObj*);
+
+ namespace ptr {
+ void foo(CheckedObj* param) {
+ consume_ref_countable_ptr(param);
+ }
+ }
+
+ namespace ref {
+ void foo(CheckedObj& param) {
+ consume_ref_countable_ref(param);
+ }
+ }
+
+ namespace ref_deref_operators {
+ void foo_ref(CheckedObj& param) {
+ consume_ref_countable_ptr(¶m);
+ }
+
+ void foo_ptr(CheckedObj* param) {
+ consume_ref_countable_ref(*param);
+ }
+ }
+
+ namespace casts {
+
+ CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+ template<class T>
+ T* bitwise_cast(T*) { return nullptr; }
+
+ void foo(CheckedObj* param) {
+ consume_ref_countable_ptr(downcast(param));
+ consume_ref_countable_ptr(bitwise_cast(param));
+ }
+ }
+}
+
+namespace param_formarding_lambda {
+ auto consume_ref_countable_ref = [](CheckedObj&) { some_function(); };
+ auto consume_ref_countable_ptr = [](CheckedObj*) { some_function(); };
+
+ namespace ptr {
+ void foo(CheckedObj* param) {
+ consume_ref_countable_ptr(param);
+ }
+ }
+
+ namespace ref {
+ void foo(CheckedObj& param) {
+ consume_ref_countable_ref(param);
+ }
+ }
+
+ namespace ref_deref_operators {
+ void foo_ref(CheckedObj& param) {
+ consume_ref_countable_ptr(¶m);
+ }
+
+ void foo_ptr(CheckedObj* param) {
+ consume_ref_countable_ref(*param);
+ }
+ }
+
+ namespace casts {
+
+ CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+ template<class T>
+ T* bitwise_cast(T*) { return nullptr; }
+
+ void foo(CheckedObj* param) {
+ consume_ref_countable_ptr(downcast(param));
+ consume_ref_countable_ptr(bitwise_cast(param));
+ }
+ }
+}
+
+namespace param_forwarding_method {
+ struct methodclass {
+ void consume_ref_countable_ref(CheckedObj&) {};
+ static void consume_ref_countable_ptr(CheckedObj*) {};
+ };
+
+ namespace ptr {
+ void foo(CheckedObj* param) {
+ methodclass::consume_ref_countable_ptr(param);
+ }
+ }
+
+ namespace ref {
+ void foo(CheckedObj& param) {
+ methodclass mc;
+ mc.consume_ref_countable_ref(param);
+ }
+ }
+
+ namespace ref_deref_operators {
+ void foo_ref(CheckedObj& param) {
+ methodclass::consume_ref_countable_ptr(¶m);
+ }
+
+ void foo_ptr(CheckedObj* param) {
+ methodclass mc;
+ mc.consume_ref_countable_ref(*param);
+ }
+ }
+
+ namespace casts {
+
+ CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+ template<class T>
+ T* bitwise_cast(T*) { return nullptr; }
+
+ void foo(CheckedObj* param) {
+ methodclass::consume_ref_countable_ptr(downcast(param));
+ methodclass::consume_ref_countable_ptr(bitwise_cast(param));
+ }
+ }
+}
+
+namespace downcast {
+ void consume_ref_countable(CheckedObj*) {}
+ CheckedObj* downcast(CheckedObj*) { return nullptr; }
+
+ void foo() {
+ CheckedPtr<CheckedObj> bar;
+ consume_ref_countable( downcast(bar.get()) );
+ }
+}
+
+namespace string_impl {
+ struct String {
+ CheckedObj* impl() { return nullptr; }
+ };
+
+ struct AtomString {
+ CheckedObj rc;
+ CheckedObj& impl() { return rc; }
+ };
+
+ void consume_ptr(CheckedObj*) {}
+ void consume_ref(CheckedObj&) {}
+
+ namespace simple {
+ void foo() {
+ String s;
+ AtomString as;
+ consume_ptr(s.impl());
+ consume_ref(as.impl());
+ }
+ }
+}
+
+namespace default_arg {
+ CheckedObj* global;
+
+ void function_with_default_arg(CheckedObj* param = global);
+ // expected-warning@-1{{Call argument for parameter 'param' is unchecked and unsafe}}
+
+ void foo() {
+ function_with_default_arg();
+ }
+}
+
+namespace cxx_member_func {
+ CheckedRef<CheckedObj> provideProtected();
+ void foo() {
+ provide()->trivial();
+ provide()->method();
+ // expected-warning@-1{{Call argument for 'this' parameter is unchecked and unsafe}}
+ provideProtected()->method();
+ (provideProtected())->method();
+ };
+}
+
+namespace cxx_member_operator_call {
+ // The hidden this-pointer argument without a corresponding parameter caused couple bugs in parameter <-> argument attribution.
+ struct Foo {
+ Foo& operator+(CheckedObj* bad);
+ friend Foo& operator-(Foo& lhs, CheckedObj* bad);
+ void operator()(CheckedObj* bad);
+ };
+
+ CheckedObj* global;
+
+ void foo() {
+ Foo f;
+ f + global;
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ f - global;
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ f(global);
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ }
+}
+
+namespace call_with_ptr_on_ref {
+ CheckedRef<CheckedObj> provideProtected();
+ void bar(CheckedObj* bad);
+ bool baz();
+ void foo(bool v) {
+ bar(v ? nullptr : provideProtected().ptr());
+ bar(baz() ? provideProtected().ptr() : nullptr);
+ bar(v ? provide() : provideProtected().ptr());
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ bar(v ? provideProtected().ptr() : provide());
+ // expected-warning@-1{{Call argument for parameter 'bad' is unchecked and unsafe}}
+ }
+}
+
+namespace call_with_explicit_temporary_obj {
+ void foo() {
+ CheckedRef { *provide() }->method();
+ CheckedPtr { provide() }->method();
+ }
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp
new file mode 100644
index 00000000000000..33f7f8272a2560
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-return-value.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+class Checkable {
+public:
+ void ref() const;
+ void deref() const;
+};
+
+class Object {
+public:
+ void ref() const;
+ void deref() const;
+ void someFunction(Checkable&);
+};
+
+RefPtr<Object> object();
+RefPtr<Checkable> protectedTargetObject();
+
+void testFunction() {
+ if (RefPtr obj = object())
+ obj->someFunction(*protectedTargetObject());
+}
diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
index 6a4c92390d773b..8579141aa7f99c 100644
--- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
+++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Checkers/BUILD.gn
@@ -142,7 +142,7 @@ static_library("Checkers") {
"WebKit/PtrTypesSemantics.cpp",
"WebKit/RawPtrRefMemberChecker.cpp",
"WebKit/RefCntblBaseVirtualDtorChecker.cpp",
- "WebKit/UncountedCallArgsChecker.cpp",
+ "WebKit/RawPtrRefCallArgsChecker.cpp",
"WebKit/Unco...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
…13708) This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a function argument which is a raw reference or a raw pointer to a CheckedPtr capable object.
0f32df4
to
6d45647
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a couple clarifying questions, otherwise LGTM!
@@ -55,10 +55,18 @@ bool isCheckedPtr(const clang::CXXRecordDecl *Class); | |||
/// not, std::nullopt if inconclusive. | |||
std::optional<bool> isUncounted(const clang::QualType T); | |||
|
|||
/// \returns true if \p Class is CheckedPtr capable AND not checked, false if | |||
/// not, std::nullopt if inconclusive. | |||
std::optional<bool> isUnchecked(const clang::QualType T); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't seem to find a reference to this overload of isUnchecked
. Do you see a use of it in future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UncheckedCallArgsChecker::isUnsafeType
calls it.
@@ -1,4 +1,4 @@ | |||
//=======- UncountedCallArgsChecker.cpp --------------------------*- C++ -*-==// | |||
//=======- RawPtrRefCallArgsChecker.cpp --------------------------*- C++ -*-==// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to have documentation for RawPtrCallArgsChecker
in checkers.rst
? Do you anticipate more generic checkers calling this checker besides UncountedCallArgsChecker
and UncheckedCallArgsChecker
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. I could imagine UncountedCallArgsChecker
and UncheckedCallArgsChecker
getting merged in the future but I don't think we'd add a new checker using RawPtrCallArgsChecker
.
Thanks for the review! |
…13708) (llvm#114522) This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a function argument which is a raw reference or a raw pointer to a CheckedPtr capable object.
…13708) (llvm#114522) This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a function argument which is a raw reference or a raw pointer to a CheckedPtr capable object.
…13708) (llvm#114522) This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a function argument which is a raw reference or a raw pointer to a CheckedPtr capable object.
This PR introduces alpha.webkit.UncheckedCallArgsChecker which detects a function argument which is a raw reference or a raw pointer to a CheckedPtr capable object.