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); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits