From: George Karpenkov Date: Wed, 16 May 2018 00:29:13 +0000 (+0000) Subject: [analyzer] Do not crash on callback for call_once passed by value X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=925ba2721e9a46cf4fdf98149a32273427602d28;p=clang [analyzer] Do not crash on callback for call_once passed by value https://bugs.llvm.org/show_bug.cgi?id=37312 rdar://40270582 Differential Revision: https://reviews.llvm.org/D46913 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@332422 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp index 61aa2e3e4a..b9fb15b2db 100644 --- a/lib/Analysis/BodyFarm.cpp +++ b/lib/Analysis/BodyFarm.cpp @@ -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, diff --git a/test/Analysis/call_once.cpp b/test/Analysis/call_once.cpp index dd4b2d4551..344de80907 100644 --- a/test/Analysis/call_once.cpp +++ b/test/Analysis/call_once.cpp @@ -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); +}