This revision was automatically updated to reflect the committed changes. Closed by commit rL315250: [Analyzer] Do not segfault on unexpected call_once implementation (authored by george.karpenkov).
Changed prior to commit: https://reviews.llvm.org/D38702?vs=118291&id=118294#toc Repository: rL LLVM https://reviews.llvm.org/D38702 Files: cfe/trunk/lib/Analysis/BodyFarm.cpp cfe/trunk/test/Analysis/call_once.cpp Index: cfe/trunk/lib/Analysis/BodyFarm.cpp =================================================================== --- cfe/trunk/lib/Analysis/BodyFarm.cpp +++ cfe/trunk/lib/Analysis/BodyFarm.cpp @@ -327,6 +327,28 @@ 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 @@ 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()); Index: cfe/trunk/test/Analysis/call_once.cpp =================================================================== --- cfe/trunk/test/Analysis/call_once.cpp +++ cfe/trunk/test/Analysis/call_once.cpp @@ -231,3 +231,12 @@ 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 +}
Index: cfe/trunk/lib/Analysis/BodyFarm.cpp =================================================================== --- cfe/trunk/lib/Analysis/BodyFarm.cpp +++ cfe/trunk/lib/Analysis/BodyFarm.cpp @@ -327,6 +327,28 @@ 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 @@ 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()); Index: cfe/trunk/test/Analysis/call_once.cpp =================================================================== --- cfe/trunk/test/Analysis/call_once.cpp +++ cfe/trunk/test/Analysis/call_once.cpp @@ -231,3 +231,12 @@ 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