r324046 - [analyzer] Fix yet-another-crash in body-farming std::call_once
George Karpenkov via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 1 17:44:08 PST 2018
Author: george.karpenkov
Date: Thu Feb 1 17:44:07 2018
New Revision: 324046
URL: http://llvm.org/viewvc/llvm-project?rev=324046&view=rev
Log:
[analyzer] Fix yet-another-crash in body-farming std::call_once
Crash occurs when parameters to the callback and to std::call_once
mismatch, and C++ is supposed to auto-construct an argument.
Filed by Alexander Kornienko in
https://bugs.llvm.org/show_bug.cgi?id=36149
rdar://37034403
Differential Revision: https://reviews.llvm.org/D42777
Modified:
cfe/trunk/lib/Analysis/BodyFarm.cpp
cfe/trunk/test/Analysis/call_once.cpp
Modified: cfe/trunk/lib/Analysis/BodyFarm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BodyFarm.cpp?rev=324046&r1=324045&r2=324046&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/BodyFarm.cpp (original)
+++ cfe/trunk/lib/Analysis/BodyFarm.cpp Thu Feb 1 17:44:07 2018
@@ -406,6 +406,16 @@ static Stmt *create_call_once(ASTContext
// reference.
for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {
const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);
+ if (PDecl &&
+ CallbackFunctionType->getParamType(ParamIdx - 2)
+ .getNonReferenceType()
+ .getCanonicalType() !=
+ PDecl->getType().getNonReferenceType().getCanonicalType()) {
+ DEBUG(llvm::dbgs() << "Types of params of the callback do not match "
+ << "params passed to std::call_once, "
+ << "ignoring the call\n");
+ return nullptr;
+ }
Expr *ParamExpr = M.makeDeclRefExpr(PDecl);
if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) {
QualType PTy = PDecl->getType().getNonReferenceType();
@@ -816,4 +826,3 @@ Stmt *BodyFarm::getBody(const ObjCMethod
return Val.getValue();
}
-
Modified: cfe/trunk/test/Analysis/call_once.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/call_once.cpp?rev=324046&r1=324045&r2=324046&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/call_once.cpp (original)
+++ cfe/trunk/test/Analysis/call_once.cpp Thu Feb 1 17:44:07 2018
@@ -9,9 +9,26 @@
void clang_analyzer_eval(bool);
-// Faking std::std::call_once implementation.
+// Faking std::call_once implementation.
namespace std {
+// Fake std::function implementation.
+template <typename>
+class function;
+class function_base {
+ public:
+ long field;
+};
+template <typename R, typename... P>
+class function<R(P...)> : function_base {
+ public:
+ R operator()(P...) const {
+
+ // Read from a super-class necessary to reproduce a crash.
+ bool a = field;
+ }
+};
+
#ifndef EMULATE_LIBSTDCPP
typedef struct once_flag_s {
unsigned long __state_ = 0;
@@ -360,3 +377,29 @@ void test_implicit_funcptr() {
clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
#endif
}
+
+int param_passed(int *x) {
+ return *x; // no-warning, as std::function is not working yet.
+}
+
+void callback_taking_func_ok(std::function<void(int*)> &innerCallback) {
+ innerCallback(nullptr);
+}
+
+// The provided callback expects an std::function, but instead a pointer
+// to a C++ function is provided.
+void callback_with_implicit_cast_ok() {
+ std::once_flag flag;
+ call_once(flag, callback_taking_func_ok, ¶m_passed);
+}
+
+void callback_taking_func(std::function<void()> &innerCallback) {
+ innerCallback();
+}
+
+// The provided callback expects an std::function, but instead a C function
+// name is provided, and C++ implicitly auto-constructs a pointer from it.
+void callback_with_implicit_cast() {
+ std::once_flag flag;
+ call_once(flag, callback_taking_func, callback_with_implicit_cast);
+}
More information about the cfe-commits
mailing list