Bugzilla is not accessible, so here's a reduced test case: $ cat test-clang__BodyFarm__getBody.cc namespace std { template <typename d, typename e> void call_once(d, e); } void g(); void f() { std::call_once(g, false); } $ clang-tidy -checks=-*,clang-analyzer* test-clang__BodyFarm__getBody.cc -- -std=c++11 -w *** SIGSEGV; stack trace: *** PC: @ 0x2f96e3a (unknown) clang::DeclContext::lookup() @ 0x532bb51 1152 FailureSignalHandler() @ 0x7f42b341f9a0 (unknown) (unknown) @ 0x2ae74c5 576 (anonymous namespace)::ASTMaker::findMemberField() @ 0x2ae59fc 704 create_call_once() @ 0x2ae5040 784 clang::BodyFarm::getBody() @ 0x2ac67af 144 clang::AnalysisDeclContext::getBody() @ 0x1c499fa 128 clang::ento::AnyFunctionCall::getRuntimeDefinition() @ 0x1cc6146 320 clang::ento::ExprEngine::defaultEvalCall() @ 0x1c61033 464 clang::ento::CheckerManager::runCheckersForEvalCall() @ 0x1cc4fc9 352 clang::ento::ExprEngine::evalCall() @ 0x1cc4e8c 432 clang::ento::ExprEngine::VisitCallExpr() @ 0x1c7da94 4000 clang::ento::ExprEngine::Visit() @ 0x1c7a821 496 clang::ento::ExprEngine::ProcessStmt() @ 0x1c7a4da 240 clang::ento::ExprEngine::processCFGElement() @ 0x1ca8ed6 128 clang::ento::CoreEngine::HandlePostStmt() @ 0x1ca87d6 496 clang::ento::CoreEngine::dispatchWorkItem() @ 0x1ca8338 544 clang::ento::CoreEngine::ExecuteWorkList() @ 0xf954d5 80 clang::ento::ExprEngine::ExecuteWorkList() @ 0xf3c612 1056 (anonymous namespace)::AnalysisConsumer::ActionExprEngine() @ 0xf3c3d1 80 (anonymous namespace)::AnalysisConsumer::RunPathSensitiveChecks() @ 0xf3c095 288 (anonymous namespace)::AnalysisConsumer::HandleCode() @ 0xf2f6e3 416 (anonymous namespace)::AnalysisConsumer::HandleDeclsCallGraph() @ 0xf2d967 336 (anonymous namespace)::AnalysisConsumer::HandleTranslationUnit() @ 0x1366eae 80 clang::MultiplexConsumer::HandleTranslationUnit() @ 0x1dc6ae6 288 clang::ParseAST() @ 0x135475a 80 clang::ASTFrontendAction::ExecuteAction() @ 0x13541f0 112 clang::FrontendAction::Execute() @ 0x1169822 496 clang::CompilerInstance::ExecuteAction() @ 0x1032ba2 464 clang::tooling::FrontendActionFactory::runInvocation() @ 0x1032a43 160 clang::tooling::ToolInvocation::runInvocation() @ 0x1031306 1840 clang::tooling::ToolInvocation::run() @ 0x1033c30 1664 clang::tooling::ClangTool::run()
On Sat, Oct 7, 2017 at 12:56 PM, Alexander Kornienko <ale...@google.com> wrote: > This revision might be the cause of https://bugs.llvm.org/show_ > bug.cgi?id=34869. I'm still working on a reduced test case. > > On Sat, Sep 30, 2017 at 2:03 AM, George Karpenkov via cfe-commits < > cfe-commits@lists.llvm.org> wrote: > >> Author: george.karpenkov >> Date: Fri Sep 29 17:03:22 2017 >> New Revision: 314571 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=314571&view=rev >> Log: >> [Analyzer] Synthesize function body for std::call_once >> >> Differential Revision: https://reviews.llvm.org/D37840 >> >> Added: >> cfe/trunk/test/Analysis/call_once.cpp >> Modified: >> cfe/trunk/lib/Analysis/BodyFarm.cpp >> >> Modified: cfe/trunk/lib/Analysis/BodyFarm.cpp >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ >> BodyFarm.cpp?rev=314571&r1=314570&r2=314571&view=diff >> ============================================================ >> ================== >> --- cfe/trunk/lib/Analysis/BodyFarm.cpp (original) >> +++ cfe/trunk/lib/Analysis/BodyFarm.cpp Fri Sep 29 17:03:22 2017 >> @@ -14,11 +14,18 @@ >> >> #include "BodyFarm.h" >> #include "clang/AST/ASTContext.h" >> +#include "clang/AST/CXXInheritance.h" >> #include "clang/AST/Decl.h" >> #include "clang/AST/Expr.h" >> +#include "clang/AST/ExprCXX.h" >> #include "clang/AST/ExprObjC.h" >> +#include "clang/AST/NestedNameSpecifier.h" >> #include "clang/Analysis/CodeInjector.h" >> +#include "clang/Basic/OperatorKinds.h" >> #include "llvm/ADT/StringSwitch.h" >> +#include "llvm/Support/Debug.h" >> + >> +#define DEBUG_TYPE "body-farm" >> >> using namespace clang; >> >> @@ -55,7 +62,9 @@ public: >> CompoundStmt *makeCompound(ArrayRef<Stmt*>); >> >> /// Create a new DeclRefExpr for the referenced variable. >> - DeclRefExpr *makeDeclRefExpr(const VarDecl *D); >> + DeclRefExpr *makeDeclRefExpr(const VarDecl *D, >> + bool RefersToEnclosingVariableOrCapture >> = false, >> + bool GetNonReferenceType = false); >> >> /// Create a new UnaryOperator representing a dereference. >> UnaryOperator *makeDereference(const Expr *Arg, QualType Ty); >> @@ -66,9 +75,24 @@ public: >> /// Create an implicit cast to a builtin boolean type. >> ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg); >> >> - // Create an implicit cast for lvalue-to-rvaluate conversions. >> + /// Create an implicit cast for lvalue-to-rvaluate conversions. >> ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty); >> >> + /// Create an implicit cast for lvalue-to-rvaluate conversions. >> + ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, >> + bool GetNonReferenceType = false); >> + >> + /// Make RValue out of variable declaration, creating a temporary >> + /// DeclRefExpr in the process. >> + ImplicitCastExpr * >> + makeLvalueToRvalue(const VarDecl *Decl, >> + bool RefersToEnclosingVariableOrCapture = false, >> + bool GetNonReferenceType = false); >> + >> + /// Create an implicit cast of the given type. >> + ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty, >> + CastKind CK = CK_LValueToRValue); >> + >> /// Create an Objective-C bool literal. >> ObjCBoolLiteralExpr *makeObjCBool(bool Val); >> >> @@ -78,6 +102,18 @@ public: >> /// Create a Return statement. >> ReturnStmt *makeReturn(const Expr *RetVal); >> >> + /// Create an integer literal. >> + IntegerLiteral *makeIntegerLiteral(uint64_t value); >> + >> + /// Create a member expression. >> + MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl, >> + bool IsArrow = false, >> + ExprValueKind ValueKind = VK_LValue); >> + >> + /// Returns a *first* member field of a record declaration with a >> given name. >> + /// \return an nullptr if no member with such a name exists. >> + NamedDecl *findMemberField(const CXXRecordDecl *RD, StringRef Name); >> + >> private: >> ASTContext &C; >> }; >> @@ -106,16 +142,16 @@ CompoundStmt *ASTMaker::makeCompound(Arr >> return new (C) CompoundStmt(C, Stmts, SourceLocation(), >> SourceLocation()); >> } >> >> -DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) { >> - DeclRefExpr *DR = >> - DeclRefExpr::Create(/* Ctx = */ C, >> - /* QualifierLoc = */ NestedNameSpecifierLoc(), >> - /* TemplateKWLoc = */ SourceLocation(), >> - /* D = */ const_cast<VarDecl*>(D), >> - /* RefersToEnclosingVariableOrCapture = */ >> false, >> - /* NameLoc = */ SourceLocation(), >> - /* T = */ D->getType(), >> - /* VK = */ VK_LValue); >> +DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D, >> + bool >> RefersToEnclosingVariableOrCapture, >> + bool GetNonReferenceType) { >> + auto Type = D->getType(); >> + if (GetNonReferenceType) >> + Type = Type.getNonReferenceType(); >> + >> + DeclRefExpr *DR = DeclRefExpr::Create( >> + C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl >> *>(D), >> + RefersToEnclosingVariableOrCapture, SourceLocation(), Type, >> VK_LValue); >> return DR; >> } >> >> @@ -125,8 +161,38 @@ UnaryOperator *ASTMaker::makeDereference >> } >> >> ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, >> QualType Ty) { >> - return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue, >> - const_cast<Expr*>(Arg), nullptr, >> VK_RValue); >> + return makeImplicitCast(Arg, Ty, CK_LValueToRValue); >> +} >> + >> +ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, >> + bool GetNonReferenceType) >> { >> + >> + QualType Type = Arg->getType(); >> + if (GetNonReferenceType) >> + Type = Type.getNonReferenceType(); >> + return makeImplicitCast(Arg, Type, CK_LValueToRValue); >> +} >> + >> +ImplicitCastExpr * >> +ASTMaker::makeLvalueToRvalue(const VarDecl *Arg, >> + bool RefersToEnclosingVariableOrCapture, >> + bool GetNonReferenceType) { >> + auto Type = Arg->getType(); >> + if (GetNonReferenceType) >> + Type = Type.getNonReferenceType(); >> + return makeLvalueToRvalue(makeDeclRefExpr(Arg, >> + >> RefersToEnclosingVariableOrCapture, >> + GetNonReferenceType), >> + Type); >> +} >> + >> +ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType >> Ty, >> + CastKind CK) { >> + return ImplicitCastExpr::Create(C, Ty, >> + /* CastKind= */ CK, >> + /* Expr= */ const_cast<Expr *>(Arg), >> + /* CXXCastPath= */ nullptr, >> + /* ExprValueKind= */ VK_RValue); >> } >> >> Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { >> @@ -161,12 +227,196 @@ ReturnStmt *ASTMaker::makeReturn(const E >> nullptr); >> } >> >> +IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t value) { >> + return IntegerLiteral::Create(C, >> + llvm::APInt( >> + /*numBits=*/C.getTypeSize(C.IntTy), >> value), >> + /*QualType=*/C.IntTy, SourceLocation()); >> +} >> + >> +MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl >> *MemberDecl, >> + bool IsArrow, >> + ExprValueKind ValueKind) { >> + >> + DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, >> AS_public); >> + return MemberExpr::Create( >> + C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), >> + SourceLocation(), MemberDecl, FoundDecl, >> + DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()), >> + /* TemplateArgumentListInfo= */ nullptr, MemberDecl->getType(), >> ValueKind, >> + OK_Ordinary); >> +} >> + >> +NamedDecl *ASTMaker::findMemberField(const CXXRecordDecl *RD, StringRef >> Name) { >> + >> + CXXBasePaths Paths( >> + /* FindAmbiguities=*/false, >> + /* RecordPaths=*/false, >> + /* DetectVirtual= */ false); >> + const IdentifierInfo &II = C.Idents.get(Name); >> + DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II); >> + >> + DeclContextLookupResult Decls = RD->lookup(DeclName); >> + for (NamedDecl *FoundDecl : Decls) >> + if (!FoundDecl->getDeclContext()->isFunctionOrMethod()) >> + return FoundDecl; >> + >> + return nullptr; >> +} >> + >> //===------------------------------------------------------ >> ----------------===// >> // Creation functions for faux ASTs. >> //===------------------------------------------------------ >> ----------------===// >> >> typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D); >> >> +static CallExpr * >> +create_call_once_funcptr_call(ASTContext &C, ASTMaker M, >> + const ParmVarDecl *Callback, >> + SmallVectorImpl<Expr *> &CallArgs) { >> + >> + return new (C) CallExpr( >> + /*ASTContext=*/C, >> + /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Callback), >> + /*args=*/CallArgs, >> + /*QualType=*/C.VoidTy, >> + /*ExprValueType=*/VK_RValue, >> + /*SourceLocation=*/SourceLocation()); >> +} >> + >> +static CallExpr * >> +create_call_once_lambda_call(ASTContext &C, ASTMaker M, >> + const ParmVarDecl *Callback, QualType >> CallbackType, >> + SmallVectorImpl<Expr *> &CallArgs) { >> + >> + CXXRecordDecl *CallbackDecl = CallbackType->getAsCXXRecordDecl(); >> + >> + assert(CallbackDecl != nullptr); >> + assert(CallbackDecl->isLambda()); >> + FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOpe >> rator(); >> + assert(callOperatorDecl != nullptr); >> + >> + DeclRefExpr *callOperatorDeclRef = >> + DeclRefExpr::Create(/* Ctx = */ C, >> + /* QualifierLoc = */ NestedNameSpecifierLoc(), >> + /* TemplateKWLoc = */ SourceLocation(), >> + const_cast<FunctionDecl *>(callOperatorDecl), >> + /* RefersToEnclosingVariableOrCapture= */ >> false, >> + /* NameLoc = */ SourceLocation(), >> + /* T = */ callOperatorDecl->getType(), >> + /* VK = */ VK_LValue); >> + >> + CallArgs.insert( >> + CallArgs.begin(), >> + M.makeDeclRefExpr(Callback, >> + /* RefersToEnclosingVariableOrCapture= */ true, >> + /* GetNonReferenceType= */ true)); >> + >> + return new (C) >> + CXXOperatorCallExpr(/*AstContext=*/C, OO_Call, >> callOperatorDeclRef, >> + /*args=*/CallArgs, >> + /*QualType=*/C.VoidTy, >> + /*ExprValueType=*/VK_RValue, >> + /*SourceLocation=*/SourceLocation(), >> FPOptions()); >> +} >> + >> +/// Create a fake body for std::call_once. >> +/// Emulates the following function body: >> +/// >> +/// \code >> +/// typedef struct once_flag_s { >> +/// unsigned long __state = 0; >> +/// } once_flag; >> +/// template<class Callable> >> +/// void call_once(once_flag& o, Callable func) { >> +/// if (!o.__state) { >> +/// func(); >> +/// } >> +/// o.__state = 1; >> +/// } >> +/// \endcode >> +static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { >> + DEBUG(llvm::dbgs() << "Generating body for call_once\n"); >> + >> + // We need at least two parameters. >> + if (D->param_size() < 2) >> + return nullptr; >> + >> + ASTMaker M(C); >> + >> + const ParmVarDecl *Flag = D->getParamDecl(0); >> + const ParmVarDecl *Callback = D->getParamDecl(1); >> + QualType CallbackType = Callback->getType().getNonReferenceType(); >> + >> + SmallVector<Expr *, 5> CallArgs; >> + >> + // All arguments past first two ones are passed to the callback. >> + for (unsigned int i = 2; i < D->getNumParams(); i++) >> + CallArgs.push_back(M.makeLvalueToRvalue(D->getParamDecl(i))); >> + >> + CallExpr *CallbackCall; >> + if (CallbackType->getAsCXXRecordDecl() && >> + CallbackType->getAsCXXRecordDecl()->isLambda()) { >> + >> + CallbackCall = >> + create_call_once_lambda_call(C, M, Callback, CallbackType, >> CallArgs); >> + } else { >> + >> + // Function pointer case. >> + 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()); >> + QualType DerefType = Deref->getType(); >> + >> + // Negation predicate. >> + UnaryOperator *FlagCheck = new (C) UnaryOperator( >> + /* input= */ >> + M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), >> DerefType, >> + CK_IntegralToBoolean), >> + /* opc= */ UO_LNot, >> + /* QualType= */ C.IntTy, >> + /* ExprValueKind= */ VK_RValue, >> + /* ExprObjectKind= */ OK_Ordinary, SourceLocation()); >> + >> + // Create assignment. >> + BinaryOperator *FlagAssignment = M.makeAssignment( >> + Deref, M.makeIntegralCast(M.makeIntegerLiteral(1), DerefType), >> DerefType); >> + >> + IfStmt *Out = new (C) >> + IfStmt(C, SourceLocation(), >> + /* IsConstexpr= */ false, >> + /* init= */ nullptr, >> + /* var= */ nullptr, >> + /* cond= */ FlagCheck, >> + /* then= */ M.makeCompound({CallbackCall, FlagAssignment})); >> + >> + return Out; >> +} >> + >> /// Create a fake body for dispatch_once. >> static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) >> { >> // Check if we have at least two parameters. >> @@ -202,15 +452,17 @@ static Stmt *create_dispatch_once(ASTCon >> ASTMaker M(C); >> >> // (1) Create the call. >> - DeclRefExpr *DR = M.makeDeclRefExpr(Block); >> - ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); >> - CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, >> - SourceLocation()); >> + CallExpr *CE = new (C) CallExpr( >> + /*ASTContext=*/C, >> + /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block), >> + /*args=*/None, >> + /*QualType=*/C.VoidTy, >> + /*ExprValueType=*/VK_RValue, >> + /*SourceLocation=*/SourceLocation()); >> >> // (2) Create the assignment to the predicate. >> - IntegerLiteral *IL = >> - IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), >> (uint64_t) 1), >> - C.IntTy, SourceLocation()); >> + IntegerLiteral *IL = M.makeIntegerLiteral(1); >> + >> BinaryOperator *B = >> M.makeAssignment( >> M.makeDereference( >> @@ -234,13 +486,20 @@ static Stmt *create_dispatch_once(ASTCon >> PredicateTy), >> PredicateTy); >> >> - UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy, >> - VK_RValue, OK_Ordinary, >> - SourceLocation()); >> + UnaryOperator *UO = new (C) UnaryOperator( >> + /* input= */ LValToRval, >> + /* opc= */ UO_LNot, >> + /* QualType= */ C.IntTy, >> + /* ExprValueKind= */ VK_RValue, >> + /* ExprObjectKind= */ OK_Ordinary, SourceLocation()); >> >> // (5) Create the 'if' statement. >> - IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, >> nullptr, >> - UO, CS); >> + IfStmt *If = new (C) IfStmt(C, SourceLocation(), >> + /* IsConstexpr= */ false, >> + /* init= */ nullptr, >> + /* var= */ nullptr, >> + /* cond= */ UO, >> + /* then= */ CS); >> return If; >> } >> >> @@ -370,8 +629,9 @@ Stmt *BodyFarm::getBody(const FunctionDe >> if (Name.startswith("OSAtomicCompareAndSwap") || >> Name.startswith("objc_atomicCompareAndSwap")) { >> FF = create_OSAtomicCompareAndSwap; >> - } >> - else { >> + } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) >> { >> + FF = create_call_once; >> + } else { >> FF = llvm::StringSwitch<FunctionFarmer>(Name) >> .Case("dispatch_sync", create_dispatch_sync) >> .Case("dispatch_once", create_dispatch_once) >> >> Added: cfe/trunk/test/Analysis/call_once.cpp >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/ >> call_once.cpp?rev=314571&view=auto >> ============================================================ >> ================== >> --- cfe/trunk/test/Analysis/call_once.cpp (added) >> +++ cfe/trunk/test/Analysis/call_once.cpp Fri Sep 29 17:03:22 2017 >> @@ -0,0 +1,233 @@ >> +// RUN: %clang_analyze_cc1 -std=c++11 -fblocks >> -analyzer-checker=core,debug.ExprInspection -w -verify %s >> + >> +void clang_analyzer_eval(bool); >> + >> +// Faking std::std::call_once implementation. >> +namespace std { >> +typedef struct once_flag_s { >> + unsigned long __state_ = 0; >> +} once_flag; >> + >> +template <class Callable, class... Args> >> +void call_once(once_flag &o, Callable func, Args... args); >> +} // namespace std >> + >> +// Check with Lambdas. >> +void test_called_warning() { >> + std::once_flag g_initialize; >> + int z; >> + >> + std::call_once(g_initialize, [&] { >> + int *x = nullptr; >> + int y = *x; // expected-warning{{Dereference of null pointer (loaded >> from variable 'x')}} >> + z = 200; >> + }); >> +} >> + >> +void test_called_on_path_inside_no_warning() { >> + std::once_flag g_initialize; >> + >> + int *x = nullptr; >> + int y = 100; >> + int z; >> + >> + std::call_once(g_initialize, [&] { >> + z = 200; >> + x = &z; >> + }); >> + >> + *x = 100; // no-warning >> + clang_analyzer_eval(z == 100); // expected-warning{{TRUE}} >> +} >> + >> +void test_called_on_path_no_warning() { >> + std::once_flag g_initialize; >> + >> + int *x = nullptr; >> + int y = 100; >> + >> + std::call_once(g_initialize, [&] { >> + x = &y; >> + }); >> + >> + *x = 100; // no-warning >> +} >> + >> +void test_called_on_path_warning() { >> + std::once_flag g_initialize; >> + >> + int y = 100; >> + int *x = &y; >> + >> + std::call_once(g_initialize, [&] { >> + x = nullptr; >> + }); >> + >> + *x = 100; // expected-warning{{Dereference of null pointer (loaded >> from variable 'x')}} >> +} >> + >> +void test_called_once_warning() { >> + std::once_flag g_initialize; >> + >> + int *x = nullptr; >> + int y = 100; >> + >> + std::call_once(g_initialize, [&] { >> + x = nullptr; >> + }); >> + >> + std::call_once(g_initialize, [&] { >> + x = &y; >> + }); >> + >> + *x = 100; // expected-warning{{Dereference of null pointer (loaded >> from variable 'x')}} >> +} >> + >> +void test_called_once_no_warning() { >> + std::once_flag g_initialize; >> + >> + int *x = nullptr; >> + int y = 100; >> + >> + std::call_once(g_initialize, [&] { >> + x = &y; >> + }); >> + >> + std::call_once(g_initialize, [&] { >> + x = nullptr; >> + }); >> + >> + *x = 100; // no-warning >> +} >> + >> +static int global = 0; >> +void funcPointer() { >> + global = 1; >> +} >> + >> +void test_func_pointers() { >> + static std::once_flag flag; >> + std::call_once(flag, &funcPointer); >> + clang_analyzer_eval(global == 1); // expected-warning{{TRUE}} >> +} >> + >> +template <class _Fp> >> +class function; // undefined >> +template <class _Rp, class... _ArgTypes> >> +struct function<_Rp(_ArgTypes...)> { >> + _Rp operator()(_ArgTypes...) const; >> + template <class _Fp> >> + function(_Fp); >> +}; >> + >> +// Note: currently we do not support calls to std::function, >> +// but the analyzer should not crash either. >> +void test_function_objects_warning() { >> + int x = 0; >> + int *y = &x; >> + >> + std::once_flag flag; >> + >> + function<void()> func = [&]() { >> + y = nullptr; >> + }; >> + >> + std::call_once(flag, func); >> + >> + func(); >> + int z = *y; >> +} >> + >> +void test_param_passing_lambda() { >> + std::once_flag flag; >> + int x = 120; >> + int y = 0; >> + >> + std::call_once(flag, [&](int p) { >> + y = p; >> + }, >> + x); >> + >> + clang_analyzer_eval(y == 120); // expected-warning{{TRUE}} >> +} >> + >> +void test_param_passing_lambda_false() { >> + std::once_flag flag; >> + int x = 120; >> + >> + std::call_once(flag, [&](int p) { >> + x = 0; >> + }, >> + x); >> + >> + clang_analyzer_eval(x == 120); // expected-warning{{FALSE}} >> +} >> + >> +void test_param_passing_stored_lambda() { >> + std::once_flag flag; >> + int x = 120; >> + int y = 0; >> + >> + auto lambda = [&](int p) { >> + y = p; >> + }; >> + >> + std::call_once(flag, lambda, x); >> + clang_analyzer_eval(y == 120); // expected-warning{{TRUE}} >> +} >> + >> +void test_multiparam_passing_lambda() { >> + std::once_flag flag; >> + int x = 120; >> + >> + std::call_once(flag, [&](int a, int b, int c) { >> + x = a + b + c; >> + }, >> + 1, 2, 3); >> + >> + clang_analyzer_eval(x == 120); // expected-warning{{FALSE}} >> + clang_analyzer_eval(x == 6); // expected-warning{{TRUE}} >> +} >> + >> +static int global2 = 0; >> +void test_param_passing_lambda_global() { >> + std::once_flag flag; >> + global2 = 0; >> + std::call_once(flag, [&](int a, int b, int c) { >> + global2 = a + b + c; >> + }, >> + 1, 2, 3); >> + clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}} >> +} >> + >> +static int global3 = 0; >> +void funcptr(int a, int b, int c) { >> + global3 = a + b + c; >> +} >> + >> +void test_param_passing_funcptr() { >> + std::once_flag flag; >> + global3 = 0; >> + >> + std::call_once(flag, &funcptr, 1, 2, 3); >> + >> + clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}} >> +} >> + >> +void test_blocks() { >> + global3 = 0; >> + std::once_flag flag; >> + std::call_once(flag, ^{ >> + global3 = 120; >> + }); >> + clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}} >> +} >> + >> +int call_once() { >> + return 5; >> +} >> + >> +void test_non_std_call_once() { >> + int x = call_once(); >> + clang_analyzer_eval(x == 5); // expected-warning{{TRUE}} >> +} >> >> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits@lists.llvm.org >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> > >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits