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, &param_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