[clang] e869103 - [webkit.UncountedLambdaCapturesChecker] Add a fallback for checking lambda captures (#119800)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Dec 15 13:32:33 PST 2024
Author: Ryosuke Niwa
Date: 2024-12-15T13:32:29-08:00
New Revision: e86910337f98e57f5b9253f7d80d5b916eb1d97e
URL: https://github.com/llvm/llvm-project/commit/e86910337f98e57f5b9253f7d80d5b916eb1d97e
DIFF: https://github.com/llvm/llvm-project/commit/e86910337f98e57f5b9253f7d80d5b916eb1d97e.diff
LOG: [webkit.UncountedLambdaCapturesChecker] Add a fallback for checking lambda captures (#119800)
Added:
Modified:
clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
index 599c2179db0f0e..ac5cf3d899d55a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
@@ -40,6 +40,7 @@ class UncountedLambdaCapturesChecker
struct LocalVisitor : DynamicRecursiveASTVisitor {
const UncountedLambdaCapturesChecker *Checker;
llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
+ llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
QualType ClsType;
explicit LocalVisitor(const UncountedLambdaCapturesChecker *Checker)
@@ -61,6 +62,24 @@ class UncountedLambdaCapturesChecker
return result && *result;
}
+ bool VisitLambdaExpr(LambdaExpr *L) override {
+ if (LambdasToIgnore.contains(L))
+ return true;
+ Checker->visitLambdaExpr(L, shouldCheckThis());
+ return true;
+ }
+
+ bool VisitVarDecl(VarDecl *VD) override {
+ auto *Init = VD->getInit();
+ if (!Init)
+ return true;
+ auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
+ if (!L)
+ return true;
+ LambdasToIgnore.insert(L); // Evaluate lambdas in VisitDeclRefExpr.
+ return true;
+ }
+
bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
if (DeclRefExprsToIgnore.contains(DRE))
return true;
@@ -73,6 +92,7 @@ class UncountedLambdaCapturesChecker
auto *L = dyn_cast_or_null<LambdaExpr>(Init->IgnoreParenCasts());
if (!L)
return true;
+ LambdasToIgnore.insert(L);
Checker->visitLambdaExpr(L, shouldCheckThis());
return true;
}
@@ -95,10 +115,10 @@ class UncountedLambdaCapturesChecker
if (ArgIndex >= CE->getNumArgs())
return true;
auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
- if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape) {
- if (auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
+ if (auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
+ LambdasToIgnore.insert(L);
+ if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
Checker->visitLambdaExpr(L, shouldCheckThis());
- }
}
++ArgIndex;
}
@@ -117,6 +137,10 @@ class UncountedLambdaCapturesChecker
if (!MD || CE->getNumArgs() < 1)
return;
auto *Arg = CE->getArg(0)->IgnoreParenCasts();
+ if (auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
+ LambdasToIgnore.insert(L); // Calling a lambda upon creation is safe.
+ return;
+ }
auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
if (!ArgRef)
return;
@@ -130,6 +154,7 @@ class UncountedLambdaCapturesChecker
if (!L)
return;
DeclRefExprsToIgnore.insert(ArgRef);
+ LambdasToIgnore.insert(L);
Checker->visitLambdaExpr(L, shouldCheckThis(),
/* ignoreParamVarDecl */ true);
}
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
index 65eee9d49106df..daff32e9940c83 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
@@ -1,16 +1,72 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.UncountedLambdaCapturesChecker -verify %s
-struct A {
- static void b();
+#include "mock-types.h"
+
+namespace WTF {
+
+namespace Detail {
+
+template<typename Out, typename... In>
+class CallableWrapperBase {
+public:
+ virtual ~CallableWrapperBase() { }
+ virtual Out call(In...) = 0;
+};
+
+template<typename, typename, typename...> class CallableWrapper;
+
+template<typename CallableType, typename Out, typename... In>
+class CallableWrapper : public CallableWrapperBase<Out, In...> {
+public:
+ explicit CallableWrapper(CallableType& callable)
+ : m_callable(callable) { }
+ Out call(In... in) final { return m_callable(in...); }
+
+private:
+ CallableType m_callable;
+};
+
+} // namespace Detail
+
+template<typename> class Function;
+
+template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>*);
+
+template <typename Out, typename... In>
+class Function<Out(In...)> {
+public:
+ using Impl = Detail::CallableWrapperBase<Out, In...>;
+
+ Function() = default;
+
+ template<typename FunctionType>
+ Function(FunctionType f)
+ : m_callableWrapper(new Detail::CallableWrapper<FunctionType, Out, In...>(f)) { }
+
+ Out operator()(In... in) const { return m_callableWrapper->call(in...); }
+ explicit operator bool() const { return !!m_callableWrapper; }
+
+private:
+ enum AdoptTag { Adopt };
+ Function(Impl* impl, AdoptTag)
+ : m_callableWrapper(impl)
+ {
+ }
+
+ friend Function adopt<Out, In...>(Impl*);
+
+ std::unique_ptr<Impl> m_callableWrapper;
};
-struct RefCountable {
- void ref() {}
- void deref() {}
- void method();
- void constMethod() const;
- int trivial() { return 123; }
- RefCountable* next();
+template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>* impl)
+{
+ return Function<Out(In...)>(impl, Function<Out(In...)>::Adopt);
+}
+
+} // namespace WTF
+
+struct A {
+ static void b();
};
RefCountable* make_obj();
@@ -185,3 +241,21 @@ void lambda_with_args(RefCountable* obj) {
};
trivial_lambda(1);
}
+
+void callFunctionOpaque(WTF::Function<void()>&&);
+void callFunction(WTF::Function<void()>&& function) {
+ someFunction();
+ function();
+}
+
+void lambda_converted_to_function(RefCountable* obj)
+{
+ callFunction([&]() {
+ obj->method();
+ // expected-warning at -1{{Implicitly captured raw-pointer 'obj' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
+ });
+ callFunctionOpaque([&]() {
+ obj->method();
+ // expected-warning at -1{{Implicitly captured raw-pointer 'obj' to ref-counted type or CheckedPtr-capable type is unsafe [webkit.UncountedLambdaCapturesChecker]}}
+ });
+}
More information about the cfe-commits
mailing list