[PATCH] D42777: [analyzer] Fix yet-another-crash in body-farming std::call_once

George Karpenkov via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 1 17:48:07 PST 2018


This revision was automatically updated to reflect the committed changes.
Closed by commit rC324046: [analyzer] Fix yet-another-crash in body-farming std::call_once (authored by george.karpenkov, committed by ).
Herald added a subscriber: cfe-commits.

Repository:
  rC Clang

https://reviews.llvm.org/D42777

Files:
  lib/Analysis/BodyFarm.cpp
  test/Analysis/call_once.cpp


Index: test/Analysis/call_once.cpp
===================================================================
--- test/Analysis/call_once.cpp
+++ test/Analysis/call_once.cpp
@@ -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 @@
   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);
+}
Index: lib/Analysis/BodyFarm.cpp
===================================================================
--- lib/Analysis/BodyFarm.cpp
+++ lib/Analysis/BodyFarm.cpp
@@ -406,6 +406,16 @@
   // 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 @@
 
   return Val.getValue();
 }
-


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D42777.132518.patch
Type: text/x-patch
Size: 2726 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180202/868f65fc/attachment.bin>


More information about the cfe-commits mailing list