[analyzer] Do not crash on callback for call_once passed by value
authorGeorge Karpenkov <ekarpenkov@apple.com>
Wed, 16 May 2018 00:29:13 +0000 (00:29 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Wed, 16 May 2018 00:29:13 +0000 (00:29 +0000)
https://bugs.llvm.org/show_bug.cgi?id=37312
rdar://40270582

Differential Revision: https://reviews.llvm.org/D46913

llvm-svn: 332422

clang/lib/Analysis/BodyFarm.cpp
clang/test/Analysis/call_once.cpp

index 61aa2e3..b9fb15b 100644 (file)
@@ -254,21 +254,24 @@ static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M,
 
   QualType Ty = Callback->getType();
   DeclRefExpr *Call = M.makeDeclRefExpr(Callback);
-  CastKind CK;
+  Expr *SubExpr;
   if (Ty->isRValueReferenceType()) {
-    CK = CK_LValueToRValue;
-  } else {
-    assert(Ty->isLValueReferenceType());
-    CK = CK_FunctionToPointerDecay;
+    SubExpr = M.makeImplicitCast(
+        Call, Ty.getNonReferenceType(), CK_LValueToRValue);
+  } else if (Ty->isLValueReferenceType() &&
+             Call->getType()->isFunctionType()) {
     Ty = C.getPointerType(Ty.getNonReferenceType());
+    SubExpr = M.makeImplicitCast(Call, Ty, CK_FunctionToPointerDecay);
+  } else if (Ty->isLValueReferenceType()
+             && Call->getType()->isPointerType()
+             && Call->getType()->getPointeeType()->isFunctionType()){
+    SubExpr = Call;
+  } else {
+    llvm_unreachable("Unexpected state");
   }
 
   return new (C)
-      CallExpr(C, M.makeImplicitCast(Call, Ty.getNonReferenceType(), CK),
-               /*args=*/CallArgs,
-               /*QualType=*/C.VoidTy,
-               /*ExprValueType=*/VK_RValue,
-               /*SourceLocation=*/SourceLocation());
+      CallExpr(C, SubExpr, CallArgs, C.VoidTy, VK_RValue, SourceLocation());
 }
 
 static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,
index dd4b2d4..344de80 100644 (file)
@@ -403,3 +403,12 @@ void callback_with_implicit_cast() {
   std::once_flag flag;
   call_once(flag, callback_taking_func, callback_with_implicit_cast);
 }
+
+std::once_flag another_once_flag;
+typedef void (*my_callback_t)(int *);
+my_callback_t callback;
+int global_int;
+
+void rdar40270582() {
+  call_once(another_once_flag, callback, &global_int);
+}