Author: george.karpenkov Date: Mon Oct 9 16:20:46 2017 New Revision: 315250
URL: http://llvm.org/viewvc/llvm-project?rev=315250&view=rev Log: [Analyzer] Do not segfault on unexpected call_once implementation Fixes https://bugs.llvm.org/show_bug.cgi?id=34869 Differential Revision: https://reviews.llvm.org/D38702 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=315250&r1=315249&r2=315250&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/BodyFarm.cpp (original) +++ cfe/trunk/lib/Analysis/BodyFarm.cpp Mon Oct 9 16:20:46 2017 @@ -327,6 +327,28 @@ static Stmt *create_call_once(ASTContext const ParmVarDecl *Flag = D->getParamDecl(0); const ParmVarDecl *Callback = D->getParamDecl(1); QualType CallbackType = Callback->getType().getNonReferenceType(); + QualType FlagType = Flag->getType().getNonReferenceType(); + CXXRecordDecl *FlagCXXDecl = FlagType->getAsCXXRecordDecl(); + if (!FlagCXXDecl) { + DEBUG(llvm::dbgs() << "Flag field is not a CXX record: " + << "unknown std::call_once implementation." + << "Ignoring the call.\n"); + return nullptr; + } + + // Note: here we are assuming libc++ implementation of call_once, + // which has a struct with a field `__state_`. + // Body farming might not work for other `call_once` implementations. + NamedDecl *FoundDecl = M.findMemberField(FlagCXXDecl, "__state_"); + ValueDecl *FieldDecl; + if (FoundDecl) { + FieldDecl = dyn_cast<ValueDecl>(FoundDecl); + } else { + DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, " + << "unable to synthesize call_once body, ignoring " + << "the call.\n"); + return nullptr; + } bool isLambdaCall = CallbackType->getAsCXXRecordDecl() && CallbackType->getAsCXXRecordDecl()->isLambda(); @@ -355,27 +377,11 @@ static Stmt *create_call_once(ASTContext CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs); } - QualType FlagType = Flag->getType().getNonReferenceType(); DeclRefExpr *FlagDecl = M.makeDeclRefExpr(Flag, /* RefersToEnclosingVariableOrCapture=*/true, /* GetNonReferenceType=*/true); - CXXRecordDecl *FlagCXXDecl = FlagType->getAsCXXRecordDecl(); - - // Note: here we are assuming libc++ implementation of call_once, - // which has a struct with a field `__state_`. - // Body farming might not work for other `call_once` implementations. - NamedDecl *FoundDecl = M.findMemberField(FlagCXXDecl, "__state_"); - ValueDecl *FieldDecl; - if (FoundDecl) { - FieldDecl = dyn_cast<ValueDecl>(FoundDecl); - } else { - DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, " - << "unable to synthesize call_once body, ignoring " - << "the call.\n"); - return nullptr; - } MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FieldDecl); assert(Deref->isLValue()); Modified: cfe/trunk/test/Analysis/call_once.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/call_once.cpp?rev=315250&r1=315249&r2=315250&view=diff ============================================================================== --- cfe/trunk/test/Analysis/call_once.cpp (original) +++ cfe/trunk/test/Analysis/call_once.cpp Mon Oct 9 16:20:46 2017 @@ -231,3 +231,12 @@ void test_non_std_call_once() { int x = call_once(); clang_analyzer_eval(x == 5); // expected-warning{{TRUE}} } + +namespace std { +template <typename d, typename e> +void call_once(d, e); +} +void g(); +void test_no_segfault_on_different_impl() { + std::call_once(g, false); // no-warning +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits