-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][analyzer] Correctly handle lambda-converted function pointers #144906
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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-static-analyzer-1 Author: None (flovent) ChangesFor lambdas that are converted to C function pointers,
clang will generate conversion method like:
Based on comment in Sema, Full diff: https://github.com/llvm/llvm-project/pull/144906.diff 3 Files Affected:
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index f6a43bf5f493b..5dcf03f7a4648 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -554,6 +554,8 @@ class SimpleFunctionCall : public AnyFunctionCall {
const FunctionDecl *getDecl() const override;
+ RuntimeDefinition getRuntimeDefinition() const override;
+
unsigned getNumArgs() const override { return getOriginExpr()->getNumArgs(); }
const Expr *getArgExpr(unsigned Index) const override {
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index f78b1b84f9df6..34fcb9b64d555 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -688,6 +688,18 @@ const FunctionDecl *SimpleFunctionCall::getDecl() const {
return getSVal(getOriginExpr()->getCallee()).getAsFunctionDecl();
}
+RuntimeDefinition SimpleFunctionCall::getRuntimeDefinition() const {
+ // Clang converts lambdas to function pointers using an implicit conversion
+ // operator, which returns the lambda's '__invoke' method. However, Sema
+ // leaves the body of '__invoke' empty (it is generated later in CodeGen), so
+ // we need to skip '__invoke' and access the lambda's operator() directly.
+ if (const auto *CMD = dyn_cast_if_present<CXXMethodDecl>(getDecl());
+ CMD && CMD->isLambdaStaticInvoker())
+ return RuntimeDefinition{CMD->getParent()->getLambdaCallOperator()};
+
+ return AnyFunctionCall::getRuntimeDefinition();
+}
+
const FunctionDecl *CXXInstanceCall::getDecl() const {
const auto *CE = cast_or_null<CallExpr>(getOriginExpr());
if (!CE)
diff --git a/clang/test/Analysis/lambda-convert-to-func-ptr.cpp b/clang/test/Analysis/lambda-convert-to-func-ptr.cpp
new file mode 100644
index 0000000000000..c2ad7cd2de34a
--- /dev/null
+++ b/clang/test/Analysis/lambda-convert-to-func-ptr.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
+
+void clang_analyzer_eval(bool);
+
+void basic() {
+ int (*ret_zero)() = []() { return 0; };
+ clang_analyzer_eval(ret_zero() == 0); // expected-warning{{TRUE}}
+}
+
+void withParam() {
+ int (*add_ten)(int) = [](int b) { return b + 10; };
+ clang_analyzer_eval(add_ten(1) == 11); // expected-warning{{TRUE}}
+}
+
+int callBack(int (*fp)(int), int x) {
+ return fp(x);
+}
+
+void passWithFunc() {
+ clang_analyzer_eval(callBack([](int x) { return x; }, 5) == 5); // expected-warning{{TRUE}}
+}
|
Hey, looks like a nice patch! I only have one question. Have you considered overriding some other |
The same occurs with assigning to Will this also be handled by this change? |
As far as i know, |
If you mean directly calling this lambda, analyzer can already analyze This patch fix the situation like this: https://godbolt.org/z/4YWPP6939
lambda |
For lambdas that are converted to C function pointers,
clang will generate conversion method like:
Based on comment in Sema,
__invoke
's function body is left empty because it's will be filled in CodeGen, so in AST analysis phase we should get lambda'soperator()
directly instead of calling__invoke
itself.