r339087 - [analyzer] NFC: Document that we support implicit argument constructors.
Author: dergachev Date: Mon Aug 6 19:22:59 2018 New Revision: 339087 URL: http://llvm.org/viewvc/llvm-project?rev=339087&view=rev Log: [analyzer] NFC: Document that we support implicit argument constructors. The change in the AST in r338135 caused us to accidentally support inlining constructors of operator implicit arguments. Previously they were hard to support because they were treated as arguments in expressions but not in declarations, but now they can be transparently treated as simple temporaries. Add tests and comments to explain how it now works. Differential Revision: https://reviews.llvm.org/D49627 Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ConstructionContext.h?rev=339087&r1=339086&r2=339087&view=diff == --- cfe/trunk/include/clang/Analysis/ConstructionContext.h (original) +++ cfe/trunk/include/clang/Analysis/ConstructionContext.h Mon Aug 6 19:22:59 2018 @@ -623,9 +623,16 @@ public: }; class ArgumentConstructionContext : public ConstructionContext { - const Expr *CE; // The call of which the context is an argument. - unsigned Index; // Which argument we're constructing. - const CXXBindTemporaryExpr *BTE; // Whether the object needs to be destroyed. + // The call of which the context is an argument. + const Expr *CE; + + // Which argument we're constructing. Note that when numbering between + // arguments and parameters is inconsistent (eg., operator calls), + // this is the index of the argument, not of the parameter. + unsigned Index; + + // Whether the object needs to be destroyed. + const CXXBindTemporaryExpr *BTE; friend class ConstructionContext; // Allows to create<>() itself. Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=339087&r1=339086&r2=339087&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Mon Aug 6 19:22:59 2018 @@ -963,3 +963,35 @@ void testCopyElisionWhenCopyConstructorH C c = C(); } } // namespace copy_elision_with_extra_arguments + + +namespace operators { +class C { +public: + C(int); + C &operator+(C Other); +}; + +// FIXME: Find construction context for the this-argument of the operator. +// CHECK: void testOperators() +// CHECK:[B1] +// CHECK-NEXT: 1: operator+ +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class operators::C &(*)(class o +// CHECK-NEXT: 3: 1 +// CHECK-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], class operators::C) +// CHECK-NEXT: 5: operators::C([B1.4]) (CXXFunctionalCastExpr, ConstructorConversion, class operato +// CHECK-NEXT: 6: [B1.5] +// CHECK-NEXT: 7: 2 +// CXX11-ELIDE-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.10], [B1.11], class operators::C) +// CXX11-NOELIDE-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.10], class operators::C) +// CXX11-NEXT: 9: operators::C([B1.8]) (CXXFunctionalCastExpr, ConstructorConversion, class operato +// CXX11-NEXT:10: [B1.9] +// CXX11-NEXT:11: [B1.10] (CXXConstructExpr, [B1.12]+1, class operators::C) +// CXX11-NEXT:12: [B1.6] + [B1.11] (OperatorCall) +// CXX17-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.10]+1, class operators::C) +// CXX17-NEXT: 9: operators::C([B1.8]) (CXXFunctionalCastExpr, ConstructorConversion, class operato +// CXX17-NEXT:10: [B1.6] + [B1.9] (OperatorCall) +void testOperators() { + C(1) + C(2); +} +} // namespace operators Modified: cfe/trunk/test/Analysis/temporaries.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temporaries.cpp?rev=339087&r1=339086&r2=339087&view=diff == --- cfe/trunk/test/Analysis/temporaries.cpp (original) +++ cfe/trunk/test/Analysis/temporaries.cpp Mon Aug 6 19:22:59 2018 @@ -986,3 +986,21 @@ void bar() { *i = 99; // no-warning } } // namespace ctor_argument + +namespace operator_implicit_argument { +struct S { + bool x; + S(bool x): x(x) {} + operator bool() const { return x; } +}; + +void foo() { + if (S(false)) { +clang_analyzer_warnIfReached(); // no-warning + } + if (S(true)) { +clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} + } +} +} // namespace operator_implicit_argument + ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r339088 - [analyzer] pr37204: Take signedness into account in getTruthValue().
Author: dergachev Date: Mon Aug 6 19:27:38 2018 New Revision: 339088 URL: http://llvm.org/viewvc/llvm-project?rev=339088&view=rev Log: [analyzer] pr37204: Take signedness into account in getTruthValue(). It now actually produces a signed APSInt when the QualType passed into it is signed, which is what any caller would expect. Fixes a couple of crashes. Differential Revision: https://reviews.llvm.org/D50363 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h cfe/trunk/test/Analysis/casts.c Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h?rev=339088&r1=339087&r2=339088&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h Mon Aug 6 19:27:38 2018 @@ -211,7 +211,8 @@ public: } const llvm::APSInt &getTruthValue(bool b, QualType T) { -return getValue(b ? 1 : 0, Ctx.getIntWidth(T), true); +return getValue(b ? 1 : 0, Ctx.getIntWidth(T), +T->isUnsignedIntegerOrEnumerationType()); } const llvm::APSInt &getTruthValue(bool b) { Modified: cfe/trunk/test/Analysis/casts.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/casts.c?rev=339088&r1=339087&r2=339088&view=diff == --- cfe/trunk/test/Analysis/casts.c (original) +++ cfe/trunk/test/Analysis/casts.c Mon Aug 6 19:27:38 2018 @@ -182,3 +182,9 @@ void testLocNonLocSymbolRemainder(int a, c += 1; } } + +void testSwitchWithSizeofs() { + switch (sizeof(char) == 1) { // expected-warning{{switch condition has boolean value}} + case sizeof(char):; // no-crash + } +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r339726 - [analyzer] Add a test forgotten in r339088.
Author: dergachev Date: Tue Aug 14 14:06:30 2018 New Revision: 339726 URL: http://llvm.org/viewvc/llvm-project?rev=339726&view=rev Log: [analyzer] Add a test forgotten in r339088. Differential Revision: https://reviews.llvm.org/D50363 Added: cfe/trunk/test/Analysis/std-c-library-functions-inlined.c Added: cfe/trunk/test/Analysis/std-c-library-functions-inlined.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/std-c-library-functions-inlined.c?rev=339726&view=auto == --- cfe/trunk/test/Analysis/std-c-library-functions-inlined.c (added) +++ cfe/trunk/test/Analysis/std-c-library-functions-inlined.c Tue Aug 14 14:06:30 2018 @@ -0,0 +1,17 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=unix.StdCLibraryFunctions -verify %s +// RUN: %clang_analyze_cc1 -triple i686-unknown-linux -analyzer-checker=unix.StdCLibraryFunctions -verify %s +// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=unix.StdCLibraryFunctions -verify %s +// RUN: %clang_analyze_cc1 -triple armv7-a15-linux -analyzer-checker=unix.StdCLibraryFunctions -verify %s +// RUN: %clang_analyze_cc1 -triple thumbv7-a15-linux -analyzer-checker=unix.StdCLibraryFunctions -verify %s + +// This test tests crashes that occur when standard functions are available +// for inlining. + +// expected-no-diagnostics + +int isdigit(int _) { return !0; } +void test_redefined_isdigit(int x) { + int (*func)(int) = isdigit; + for (; func(x);) // no-crash +; +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r339727 - [CFG] [analyzer] Find argument constructors in CXXTemporaryObjectExprs.
Author: dergachev Date: Tue Aug 14 14:10:46 2018 New Revision: 339727 URL: http://llvm.org/viewvc/llvm-project?rev=339727&view=rev Log: [CFG] [analyzer] Find argument constructors in CXXTemporaryObjectExprs. CXXTemporaryObjectExpr is a sub-class of CXXConstructExpr. If it has arguments that are structures passed by value, their respective constructors need to be handled by providing a ConstructionContext, like for regular function calls and for regular constructors. Differential Revision: https://reviews.llvm.org/D50487 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=339727&r1=339726&r2=339727&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Tue Aug 14 14:10:46 2018 @@ -4352,6 +4352,11 @@ CFGBlock *CFGBuilder::VisitCXXFunctional CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, AddStmtChoice asc) { + // If the constructor takes objects as arguments by value, we need to properly + // construct these objects. Construction contexts we find here aren't for the + // constructor C, they're for its arguments only. + findConstructionContextsForArguments(C); + autoCreateBlock(); appendConstructor(Block, C); return VisitChildren(C); Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=339727&r1=339726&r2=339727&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Tue Aug 14 14:10:46 2018 @@ -820,6 +820,7 @@ public: class E { public: E(D d); + E(D d1, D d2); }; void useC(C c); @@ -939,6 +940,38 @@ void passArgumentWithDestructorByReferen void passArgumentIntoAnotherConstructor() { E e = E(D()); } + + +// CHECK: void passTwoArgumentsIntoAnotherConstructor() +// CXX11-ELIDE: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class argument_constructors::D) +// CXX11-NOELIDE: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], class argument_constructors::D) +// CXX11-NEXT: 2: [B1.1] (BindTemporary) +// CXX11-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT: 4: [B1.3] +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], [B1.13]+0, class argument_constructors::D) +// CXX11-NEXT: 6: [B1.5] (BindTemporary) +// CXX11-ELIDE-NEXT: 7: argument_constructors::D() (CXXConstructExpr, [B1.8], [B1.10], [B1.11], class argument_constructors::D) +// CXX11-NOELIDE-NEXT: 7: argument_constructors::D() (CXXConstructExpr, [B1.8], [B1.10], class argument_constructors::D) +// CXX11-NEXT: 8: [B1.7] (BindTemporary) +// CXX11-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT:10: [B1.9] +// CXX11-NEXT:11: [B1.10] (CXXConstructExpr, [B1.12], [B1.13]+1, class argument_constructors::D) +// CXX11-NEXT:12: [B1.11] (BindTemporary) +// CXX11-NEXT:13: argument_constructors::E([B1.6], [B1.12]) (CXXConstructExpr, class argument_constructors::E) +// CXX11-NEXT:14: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT:15: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT:16: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT:17: ~argument_constructors::D() (Temporary object destructor) +// CXX17: 1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.5]+0, class argument_constructors::D) +// CXX17-NEXT: 2: [B1.1] (BindTemporary) +// CXX17-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.5]+1, class argument_constructors::D) +// CXX17-NEXT: 4: [B1.3] (BindTemporary) +// CXX17-NEXT: 5: argument_constructors::E([B1.2], [B1.4]) (CXXConstructExpr, class argument_constructors::E) +// CXX17-NEXT: 6: ~argument_constructors::D() (Temporary object destructor) +// CXX17-NEXT: 7: ~argument_constructors::D() (Temporary object destructor) +void passTwoArgumentsIntoAnotherConstructor() { + E(D(), D()); +} } // end namespace argument_constructors namespace copy_elision_with_extra_arguments { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r339745 - [analyzer] Add support for constructors of arguments.
Author: dergachev Date: Tue Aug 14 17:33:55 2018 New Revision: 339745 URL: http://llvm.org/viewvc/llvm-project?rev=339745&view=rev Log: [analyzer] Add support for constructors of arguments. Once CFG-side support for argument construction contexts landed in r338436, the analyzer could make use of them to evaluate argument constructors properly. When evaluated as calls, constructors of arguments now use the variable region of the parameter as their target. The corresponding stack frame does not yet exist when the parameter is constructed, and this stack frame is created eagerly. Construction of functions whose body is unavailable and of virtual functions is not yet supported. Part of the reason is the analyzer doesn't consistently use canonical declarations o identify the function in these cases, and every re-declaration or potential override comes with its own set of parameter declarations. Also it is less important because if the function is not inlined, there's usually no benefit in inlining the argument constructor. Differential Revision: https://reviews.llvm.org/D49443 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp cfe/trunk/test/Analysis/copy-elision.cpp cfe/trunk/test/Analysis/temporaries.cpp cfe/trunk/test/Analysis/temporaries.mm Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h?rev=339745&r1=339744&r2=339745&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h Tue Aug 14 17:33:55 2018 @@ -428,21 +428,23 @@ public: bool isArgumentConstructedDirectly(unsigned Index) const { // This assumes that the object was not yet removed from the state. return ExprEngine::getObjectUnderConstruction( -getState(), {getOriginExpr(), Index}, getCalleeStackFrame()).hasValue(); +getState(), {getOriginExpr(), Index}, getLocationContext()).hasValue(); } /// Some calls have parameter numbering mismatched from argument numbering. /// This function converts an argument index to the corresponding /// parameter index. Returns None is the argument doesn't correspond /// to any parameter variable. - Optional getAdjustedParameterIndex(unsigned ArgumentIndex) const { -if (dyn_cast_or_null(getOriginExpr()) && -dyn_cast_or_null(getDecl())) { - // For member operator calls argument 0 on the expression corresponds - // to implicit this-parameter on the declaration. - return (ArgumentIndex > 0) ? Optional(ArgumentIndex - 1) : None; -} -return ArgumentIndex; + virtual Optional + getAdjustedParameterIndex(unsigned ASTArgumentIndex) const { +return ASTArgumentIndex; + } + + /// Some call event sub-classes conveniently adjust mismatching AST indices + /// to match parameter indices. This function converts an argument index + /// as understood by CallEvent to the argument index as understood by the AST. + virtual unsigned getASTArgumentIndex(unsigned CallArgumentIndex) const { +return CallArgumentIndex; } // Iterator access to formal parameters and their types. @@ -769,6 +771,20 @@ public: static bool classof(const CallEvent *CA) { return CA->getKind() == CE_CXXMemberOperator; } + + Optional + getAdjustedParameterIndex(unsigned ASTArgumentIndex) const override { +// For member operator calls argument 0 on the expression corresponds +// to implicit this-parameter on the declaration. +return (ASTArgumentIndex > 0) ? Optional(ASTArgumentIndex - 1) + : None; + } + + unsigned getASTArgumentIndex(unsigned CallArgumentIndex) const override { +// For member operator calls argument 0 on the expression corresponds +// to implicit this-parameter on the declaration. +return CallArgumentIndex + 1; + } }; /// Represents an implicit call to a C++ destructor. Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=339745&r1=339744&r2=339745&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/tru
r332303 - [analyzer] Re-apply r331096 "CStringChecker: Add support for BSD strlcpy()...".
Author: dergachev Date: Mon May 14 15:32:24 2018 New Revision: 332303 URL: http://llvm.org/viewvc/llvm-project?rev=332303&view=rev Log: [analyzer] Re-apply r331096 "CStringChecker: Add support for BSD strlcpy()...". Fixed after revert in r331401. Patch by David Carlier! Differential Revision: https://reviews.llvm.org/D45177 Added: cfe/trunk/test/Analysis/bsd-string.c Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=332303&r1=332302&r2=332303&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Mon May 14 15:32:24 2018 @@ -97,14 +97,17 @@ public: void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; + void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const; void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd, bool isBounded, -bool isAppending) const; +bool isAppending, +bool returnPtr = true) const; void evalStrcat(CheckerContext &C, const CallExpr *CE) const; void evalStrncat(CheckerContext &C, const CallExpr *CE) const; + void evalStrlcat(CheckerContext &C, const CallExpr *CE) const; void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; @@ -1393,6 +1396,18 @@ void CStringChecker::evalStpcpy(CheckerC /* isAppending = */ false); } +void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const { + if (CE->getNumArgs() < 3) +return; + + // char *strlcpy(char *dst, const char *src, size_t n); + evalStrcpyCommon(C, CE, + /* returnEnd = */ true, + /* isBounded = */ true, + /* isAppending = */ false, + /* returnPtr = */ false); +} + void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { if (CE->getNumArgs() < 2) return; @@ -1415,9 +1430,21 @@ void CStringChecker::evalStrncat(Checker /* isAppending = */ true); } +void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const { + if (CE->getNumArgs() < 3) +return; + + //char *strlcat(char *s1, const char *s2, size_t n); + evalStrcpyCommon(C, CE, + /* returnEnd = */ false, + /* isBounded = */ true, + /* isAppending = */ true, + /* returnPtr = */ false); +} + void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd, bool isBounded, - bool isAppending) const { + bool isAppending, bool returnPtr) const { CurrentFunctionDescription = "string copy function"; ProgramStateRef state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); @@ -1455,6 +1482,11 @@ void CStringChecker::evalStrcpyCommon(Ch SVal maxLastElementIndex = UnknownVal(); const char *boundWarning = nullptr; + state = CheckOverlap(C, state, isBounded ? CE->getArg(2) : CE->getArg(1), Dst, srcExpr); + + if (!state) +return; + // If the function is strncpy, strncat, etc... it is bounded. if (isBounded) { // Get the max number of characters to copy. @@ -1658,16 +1690,22 @@ void CStringChecker::evalStrcpyCommon(Ch finalStrLength = amountCopied; } - // The final result of the function will either be a pointer past the last - // copied element, or a pointer to the start of the destination buffer. - SVal Result = (returnEnd ? UnknownVal() : DstVal); + SVal Result; + + if (returnPtr) { +// The final result of the function will either be a pointer past the last +// copied element, or a pointer to the start of the destination buffer. +Result = (returnEnd ? UnknownVal() : DstVal); + } else { +Result = finalStrLength; + } assert(state); // If the destination is a MemRegion, try to check for a buffer overflow and // record the new string length. if (Optional dstRegVal = - DstVal.getAs()) { + DstVal.getAs()) { QualType ptrTy = Dst->getType(); // If we have an exact value on a bounded copy, use that to check for @@ -1675,9 +1713,9 @@ void CStringChecker::evalStrcpyCommon(Ch if (boundWarning) { if (Optional maxLastNL = maxLastElementIndex.getAs()) { SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO
r332417 - [analyzer] Make plist-html diagnostic consumer produce multi-file reports.
Author: dergachev Date: Tue May 15 17:11:24 2018 New Revision: 332417 URL: http://llvm.org/viewvc/llvm-project?rev=332417&view=rev Log: [analyzer] Make plist-html diagnostic consumer produce multi-file reports. Previously plist-html output produced multi-file HTML reports but only single-file Plist reports. Change plist-html output to produce multi-file Plist reports as well. Differential Revision: https://reviews.llvm.org/D46902 Added: cfe/trunk/test/Analysis/diagnostics/plist-multi-file.c cfe/trunk/test/Analysis/diagnostics/plist-multi-file.h Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp?rev=332417&r1=332416&r2=332417&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Tue May 15 17:11:24 2018 @@ -73,7 +73,7 @@ void ento::createPlistHTMLDiagnosticCons const Preprocessor &PP) { createHTMLDiagnosticConsumer(AnalyzerOpts, C, llvm::sys::path::parent_path(prefix), PP); - createPlistDiagnosticConsumer(AnalyzerOpts, C, prefix, PP); + createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP); } void ento::createTextPathDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, Added: cfe/trunk/test/Analysis/diagnostics/plist-multi-file.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/diagnostics/plist-multi-file.c?rev=332417&view=auto == --- cfe/trunk/test/Analysis/diagnostics/plist-multi-file.c (added) +++ cfe/trunk/test/Analysis/diagnostics/plist-multi-file.c Tue May 15 17:11:24 2018 @@ -0,0 +1,205 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-html -o %t.plist -verify %s +// RUN: FileCheck --input-file=%t.plist %s + +#include "plist-multi-file.h" + +void bar() { + foo(0); +} + +// CHECK: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line7 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line7 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line7 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'ptr' +// CHECK-NEXT: message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'ptr' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line7 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line7 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line7 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'foo' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'foo' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line1 +// CHECK-NEXT: col1 +// CHECK-NEXT: file1 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'bar' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'bar' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1 +// CHECK-NEXT: col1 +// CHECK-NEXT: file1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line1 +// CHECK-NEXT: col4 +// CHECK-NEXT: file1 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line2 +// CHECK-NEXT: col3 +// CHECK-NEXT: file1 +// CHECK
r333326 - [analyzer] Add security checks for bcmp(), bcopy(), bzero().
Author: dergachev Date: Fri May 25 17:04:26 2018 New Revision: 26 URL: http://llvm.org/viewvc/llvm-project?rev=26&view=rev Log: [analyzer] Add security checks for bcmp(), bcopy(), bzero(). These functions are obsolete. The analyzer would advice to replace them with memcmp(), memcpy() or memmove(), or memset(). Patch by Tom Rix! Differential Revision: https://reviews.llvm.org/D41881 Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td cfe/trunk/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp cfe/trunk/test/Analysis/security-syntax-checks.m cfe/trunk/www/analyzer/available_checks.html Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td?rev=26&r1=25&r2=26&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td Fri May 25 17:04:26 2018 @@ -373,6 +373,15 @@ def PaddingChecker : Checker<"Padding">, //===--===// let ParentPackage = InsecureAPI in { + def bcmp : Checker<"bcmp">, +HelpText<"Warn on uses of the 'bcmp' function">, +DescFile<"CheckSecuritySyntaxOnly.cpp">; + def bcopy : Checker<"bcopy">, +HelpText<"Warn on uses of the 'bcopy' function">, +DescFile<"CheckSecuritySyntaxOnly.cpp">; + def bzero : Checker<"bzero">, +HelpText<"Warn on uses of the 'bzero' function">, +DescFile<"CheckSecuritySyntaxOnly.cpp">; def gets : Checker<"gets">, HelpText<"Warn on uses of the 'gets' function">, DescFile<"CheckSecuritySyntaxOnly.cpp">; Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp?rev=26&r1=25&r2=26&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp Fri May 25 17:04:26 2018 @@ -37,6 +37,9 @@ static bool isArc4RandomAvailable(const namespace { struct ChecksFilter { + DefaultBool check_bcmp; + DefaultBool check_bcopy; + DefaultBool check_bzero; DefaultBool check_gets; DefaultBool check_getpw; DefaultBool check_mktemp; @@ -47,6 +50,9 @@ struct ChecksFilter { DefaultBool check_FloatLoopCounter; DefaultBool check_UncheckedReturn; + CheckName checkName_bcmp; + CheckName checkName_bcopy; + CheckName checkName_bzero; CheckName checkName_gets; CheckName checkName_getpw; CheckName checkName_mktemp; @@ -89,6 +95,9 @@ public: // Checker-specific methods. void checkLoopConditionForFloat(const ForStmt *FS); + void checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD); + void checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD); + void checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD); void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD); void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD); void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD); @@ -129,6 +138,9 @@ void WalkAST::VisitCallExpr(CallExpr *CE // Set the evaluation function by switching on the callee name. FnCheck evalFunction = llvm::StringSwitch(Name) +.Case("bcmp", &WalkAST::checkCall_bcmp) +.Case("bcopy", &WalkAST::checkCall_bcopy) +.Case("bzero", &WalkAST::checkCall_bzero) .Case("gets", &WalkAST::checkCall_gets) .Case("getpw", &WalkAST::checkCall_getpw) .Case("mktemp", &WalkAST::checkCall_mktemp) @@ -296,6 +308,132 @@ void WalkAST::checkLoopConditionForFloat } //===--===// +// Check: Any use of bcmp. +// CWE-477: Use of Obsolete Functions +// bcmp was deprecated in POSIX.1-2008 +//===--===// + +void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) { + if (!filter.check_bcmp) +return; + + const FunctionProtoType *FPT = FD->getType()->getAs(); + if (!FPT) +return; + + // Verify that the function takes three arguments. + if (FPT->getNumParams() != 3) +return; + + for (int i = 0; i < 2; i++) { +// Verify the first and second argument type is void*. +const PointerType *PT = FPT->getParamType(i)->getAs(); +if (!PT) + return; + +if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy) + return; + } + + // Verify the third argument type is integer. + if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType()) +return; + + // Issue a warning. + PathDiagnosticLocation CELoc = +PathDiagnosticLocation:
r314218 - [analyzer] Keep track of design discusions as part of analyzer documentation.
Author: dergachev Date: Tue Sep 26 08:49:53 2017 New Revision: 314218 URL: http://llvm.org/viewvc/llvm-project?rev=314218&view=rev Log: [analyzer] Keep track of design discusions as part of analyzer documentation. Create a directory to store discussions on potentially useful features that are not yet implemented in the analyzer. Fill it with a discussion on representing checker-specific parts of the program state for C++ object modeling, that occured in D35216. Differential Revision: https://reviews.llvm.org/D36737 Added: cfe/trunk/docs/analyzer/DesignDiscussions/ cfe/trunk/docs/analyzer/DesignDiscussions/InitializerLists.rst Added: cfe/trunk/docs/analyzer/DesignDiscussions/InitializerLists.rst URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/analyzer/DesignDiscussions/InitializerLists.rst?rev=314218&view=auto == --- cfe/trunk/docs/analyzer/DesignDiscussions/InitializerLists.rst (added) +++ cfe/trunk/docs/analyzer/DesignDiscussions/InitializerLists.rst Tue Sep 26 08:49:53 2017 @@ -0,0 +1,321 @@ +This discussion took place in https://reviews.llvm.org/D35216 +"Escape symbols when creating std::initializer_list". + +It touches problems of modelling C++ standard library constructs in general, +including modelling implementation-defined fields within C++ standard library +objects, in particular constructing objects into pointers held by such fields, +and separation of responsibilities between analyzer's core and checkers. + +**Artem:** + +I've seen a few false positives that appear because we construct +C++11 std::initializer_list objects with brace initializers, and such +construction is not properly modeled. For instance, if a new object is +constructed on the heap only to be put into a brace-initialized STL container, +the object is reported to be leaked. + +Approach (0): This can be trivially fixed by this patch, which causes pointers +passed into initializer list expressions to immediately escape. + +This fix is overly conservative though. So i did a bit of investigation as to +how model std::initializer_list better. + +According to the standard, std::initializer_list is an object that has +methods begin(), end(), and size(), where begin() returns a pointer to continous +array of size() objects of type T, and end() is equal to begin() plus size(). +The standard does hint that it should be possible to implement +std::initializer_list as a pair of pointers, or as a pointer and a size +integer, however specific fields that the object would contain are an +implementation detail. + +Ideally, we should be able to model the initializer list's methods precisely. +Or, at least, it should be possible to explain to the analyzer that the list +somehow "takes hold" of the values put into it. Initializer lists can also be +copied, which is a separate story that i'm not trying to address here. + +The obvious approach to modeling std::initializer_list in a checker would be to +construct a SymbolMetadata for the memory region of the initializer list object, +which would be of type T* and represent begin(), so we'd trivially model begin() +as a function that returns this symbol. The array pointed to by that symbol +would be bindLoc()ed to contain the list's contents (probably as a CompoundVal +to produce less bindings in the store). Extent of this array would represent +size() and would be equal to the length of the list as written. + +So this sounds good, however apparently it does nothing to address our false +positives: when the list escapes, our RegionStoreManager is not magically +guessing that the metadata symbol attached to it, together with its contents, +should also escape. In fact, it's impossible to trigger a pointer escape from +within the checker. + +Approach (1): If only we enabled ProgramState::bindLoc(..., notifyChanges=true) +to cause pointer escapes (not only region changes) (which sounds like the right +thing to do anyway) such checker would be able to solve the false positives by +triggering escapes when binding list elements to the list. However, it'd be as +conservative as the current patch's solution. Ideally, we do not want escapes to +happen so early. Instead, we'd prefer them to be delayed until the list itself +escapes. + +So i believe that escaping metadata symbols whenever their base regions escape +would be the right thing to do. Currently we didn't think about that because we +had neither pointer-type metadatas nor non-pointer escapes. + +Approach (2): We could teach the Store to scan itself for bindings to +metadata-symbolic-based regions during scanReachableSymbols() whenever a region +turns out to be reachable. This requires no work on checker side, but it sounds +performance-heavy. + +Approach (3): We could let checkers maintain the set of active metadata symbols +in the program state (ideally somewhere in the Store, which sounds weird but +causes the smallest amount of layering violation
r314287 - [analyzer] Fix and refactor bugreporter::getDerefExpr() API.
Author: dergachev Date: Wed Sep 27 02:33:37 2017 New Revision: 314287 URL: http://llvm.org/viewvc/llvm-project?rev=314287&view=rev Log: [analyzer] Fix and refactor bugreporter::getDerefExpr() API. This API is used by checkers (and other entities) in order to track where does a value originate from, by jumping from an expression value of which is equal to that value to the expression from which this value has "appeared". For example, it may be an lvalue from which the rvalue was loaded, or a function call from which the dereferenced pointer was returned. The function now avoids incorrectly unwrapping implicit lvalue-to-rvalue casts, which caused crashes and incorrect intermediate diagnostic pieces. It also no longer relies on how the expression is written when guessing what it means. Fixes pr34373 and pr34731. rdar://problem/33594502 Differential Revision: https://reviews.llvm.org/D37023 Added: cfe/trunk/test/Analysis/null-deref-path-notes.c cfe/trunk/test/Analysis/null-deref-path-notes.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp cfe/trunk/test/Analysis/null-deref-path-notes.m Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp?rev=314287&r1=314286&r2=314287&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp Wed Sep 27 02:33:37 2017 @@ -42,48 +42,68 @@ bool bugreporter::isDeclRefExprToReferen return false; } +/// Given that expression S represents a pointer that would be dereferenced, +/// try to find a sub-expression from which the pointer came from. +/// This is used for tracking down origins of a null or undefined value: +/// "this is null because that is null because that is null" etc. +/// We wipe away field and element offsets because they merely add offsets. +/// We also wipe away all casts except lvalue-to-rvalue casts, because the +/// latter represent an actual pointer dereference; however, we remove +/// the final lvalue-to-rvalue cast before returning from this function +/// because it demonstrates more clearly from where the pointer rvalue was +/// loaded. Examples: +/// x->y.z ==> x (lvalue) +/// foo()->y.z ==> foo() (rvalue) const Expr *bugreporter::getDerefExpr(const Stmt *S) { - // Pattern match for a few useful cases: - // a[0], p->f, *p const Expr *E = dyn_cast(S); if (!E) return nullptr; - E = E->IgnoreParenCasts(); while (true) { -if (const BinaryOperator *B = dyn_cast(E)) { - assert(B->isAssignmentOp()); - E = B->getLHS()->IgnoreParenCasts(); - continue; -} -else if (const UnaryOperator *U = dyn_cast(E)) { - if (U->getOpcode() == UO_Deref) -return U->getSubExpr()->IgnoreParenCasts(); -} -else if (const MemberExpr *ME = dyn_cast(E)) { - if (ME->isImplicitAccess()) { -return ME; - } else if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { -return ME->getBase()->IgnoreParenCasts(); +if (const CastExpr *CE = dyn_cast(E)) { + if (CE->getCastKind() == CK_LValueToRValue) { +// This cast represents the load we're looking for. +break; + } + E = CE->getSubExpr(); +} else if (isa(E)) { + // Probably more arithmetic can be pattern-matched here, + // but for now give up. + break; +} else if (const UnaryOperator *U = dyn_cast(E)) { + if (U->getOpcode() == UO_Deref) { +// Operators '*' and '&' don't actually mean anything. +// We look at casts instead. +E = U->getSubExpr(); } else { -// If we have a member expr with a dot, the base must have been -// dereferenced. -return getDerefExpr(ME->getBase()); +// Probably more arithmetic can be pattern-matched here, +// but for now give up. +break; } } -else if (const ObjCIvarRefExpr *IvarRef = dyn_cast(E)) { - return IvarRef->getBase()->IgnoreParenCasts(); -} -else if (const ArraySubscriptExpr *AE = dyn_cast(E)) { - return getDerefExpr(AE->getBase()); -} -else if (isa(E)) { - return E; +// Pattern match for a few useful cases: a[0], p->f, *p etc. +else if (const MemberExpr *ME = dyn_cast(E)) { + E = ME->getBase(); +} else if (const ObjCIvarRefExpr *IvarRef = dyn_cast(E)) { + E = IvarRef->getBase(); +} else if (const ArraySubscriptExpr *AE = dyn_cast(E)) { + E = AE->getBase(); +} else if (const ParenExpr *PE = dyn_cast(E)) { + E = PE->getSubExpr(); +} else { + // Other arbitrary stuff. + break; } -break; } - return nullptr; + // Special case: remove the final lvalue-to-rvalue cast, but do not recurse + // deeper into the sub-expression. This wa
r314290 - [analyzer] Match more patterns in bugreporter::getDerefExpr() API.
Author: dergachev Date: Wed Sep 27 02:50:45 2017 New Revision: 314290 URL: http://llvm.org/viewvc/llvm-project?rev=314290&view=rev Log: [analyzer] Match more patterns in bugreporter::getDerefExpr() API. This function can now track null pointer through simple pointer arithmetic, such as '*&*(p + 2)' => 'p' and so on, displaying intermediate diagnostic pieces for the user to understand where the null pointer is coming from. Differential Revision: https://reviews.llvm.org/D37025 Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c cfe/trunk/test/Analysis/null-deref-path-notes.c cfe/trunk/test/Analysis/nullptr.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp?rev=314290&r1=314289&r2=314290&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp Wed Sep 27 02:50:45 2017 @@ -66,12 +66,24 @@ const Expr *bugreporter::getDerefExpr(co break; } E = CE->getSubExpr(); -} else if (isa(E)) { - // Probably more arithmetic can be pattern-matched here, - // but for now give up. - break; +} else if (const BinaryOperator *B = dyn_cast(E)) { + // Pointer arithmetic: '*(x + 2)' -> 'x') etc. + if (B->getType()->isPointerType()) { +if (B->getLHS()->getType()->isPointerType()) { + E = B->getLHS(); +} else if (B->getRHS()->getType()->isPointerType()) { + E = B->getRHS(); +} else { + break; +} + } else { +// Probably more arithmetic can be pattern-matched here, +// but for now give up. +break; + } } else if (const UnaryOperator *U = dyn_cast(E)) { - if (U->getOpcode() == UO_Deref) { + if (U->getOpcode() == UO_Deref || U->getOpcode() == UO_AddrOf || + (U->isIncrementDecrementOp() && U->getType()->isPointerType())) { // Operators '*' and '&' don't actually mean anything. // We look at casts instead. E = U->getSubExpr(); Modified: cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c?rev=314290&r1=314289&r2=314290&view=diff == --- cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c (original) +++ cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c Wed Sep 27 02:50:45 2017 @@ -169,6 +169,18 @@ void idcTrackZeroValueThroughUnaryPointe *x = 7; // no-warning } +void idcTrackZeroValueThroughManyUnaryPointerOperatorsWithAssignment(struct S *s) { + idc(s); + int *x = &*&(s->f1); + *x = 7; // no-warning +} + +void idcTrackZeroValueThroughManyUnaryPointerOperatorsWithAssignmentAndUnaryIncrement(struct S *s) { + idc(s); + int *x = &*&((++s)->f1); + *x = 7; // no-warning +} + struct S2 { int a[1]; Modified: cfe/trunk/test/Analysis/null-deref-path-notes.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/null-deref-path-notes.c?rev=314290&r1=314289&r2=314290&view=diff == --- cfe/trunk/test/Analysis/null-deref-path-notes.c (original) +++ cfe/trunk/test/Analysis/null-deref-path-notes.c Wed Sep 27 02:50:45 2017 @@ -4,7 +4,7 @@ // of the null pointer for path notes. Apparently, not much actual tracking // needs to be done in this example. void pr34373() { - int *a = 0; + int *a = 0; // expected-note{{'a' initialized to a null pointer value}} (a + 0)[0]; // expected-warning{{Array access results in a null pointer dereference}} // expected-note@-1{{Array access results in a null pointer dereference}} } Modified: cfe/trunk/test/Analysis/nullptr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/nullptr.cpp?rev=314290&r1=314289&r2=314290&view=diff == --- cfe/trunk/test/Analysis/nullptr.cpp (original) +++ cfe/trunk/test/Analysis/nullptr.cpp Wed Sep 27 02:50:45 2017 @@ -1,11 +1,12 @@ -// RUN: %clang_analyze_cc1 -std=c++11 -Wno-conversion-null -analyzer-checker=core,debug.ExprInspection -analyzer-store region -verify %s +// RUN: %clang_analyze_cc1 -std=c++11 -Wno-conversion-null -analyzer-checker=core,debug.ExprInspection -analyzer-store region -analyzer-output=text -verify %s void clang_analyzer_eval(int); // test to see if nullptr is detected as a null pointer void foo1(void) { - char *np = nullptr; + char *np = nullptr; // expected-note{{'np' initialized to a null pointer value}} *np = 0; // expected-warning{{Dereference of null pointer
r314298 - [analyzer] Fix an outdated comment in a test. NFC.
Author: dergachev Date: Wed Sep 27 03:59:06 2017 New Revision: 314298 URL: http://llvm.org/viewvc/llvm-project?rev=314298&view=rev Log: [analyzer] Fix an outdated comment in a test. NFC. Modified: cfe/trunk/test/Analysis/null-deref-path-notes.c Modified: cfe/trunk/test/Analysis/null-deref-path-notes.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/null-deref-path-notes.c?rev=314298&r1=314297&r2=314298&view=diff == --- cfe/trunk/test/Analysis/null-deref-path-notes.c (original) +++ cfe/trunk/test/Analysis/null-deref-path-notes.c Wed Sep 27 03:59:06 2017 @@ -1,8 +1,7 @@ // RUN: %clang_analyze_cc1 -w -x c -analyzer-checker=core -analyzer-output=text -verify %s // Avoid the crash when finding the expression for tracking the origins -// of the null pointer for path notes. Apparently, not much actual tracking -// needs to be done in this example. +// of the null pointer for path notes. void pr34373() { int *a = 0; // expected-note{{'a' initialized to a null pointer value}} (a + 0)[0]; // expected-warning{{Array access results in a null pointer dereference}} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r314910 - [analyzer] Fix autodetection of binding types.
Author: dergachev Date: Wed Oct 4 08:59:40 2017 New Revision: 314910 URL: http://llvm.org/viewvc/llvm-project?rev=314910&view=rev Log: [analyzer] Fix autodetection of binding types. In ProgramState::getSVal(Location, Type) API which dereferences a pointer value, when the optional Type parameter is not supplied and the Location is not typed, type should have been guessed on a best-effort basis by inspecting the Location more deeply. However, this never worked; the auto-detected type was instead a pointer type to the correct type. Fixed the issue and added various test cases to demonstrate which parts of the analyzer were affected (uninitialized pointer argument checker, C++ trivial copy modeling, Google test API modeling checker). Additionally, autodetected void types are automatically replaced with char, in order to simplify checker APIs. Which means that if the location is a void pointer, getSVal() would read the first byte through this pointer and return its symbolic value. Fixes pr34305. Differential Revision: https://reviews.llvm.org/D38358 Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp cfe/trunk/test/Analysis/ctor.mm cfe/trunk/test/Analysis/exercise-ps.c cfe/trunk/test/Analysis/gtest.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=314910&r1=314909&r2=314910&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Wed Oct 4 08:59:40 2017 @@ -1393,16 +1393,19 @@ SVal RegionStoreManager::getBinding(Regi return UnknownVal(); } - if (isa(MR) || - isa(MR) || - isa(MR)) { + if (!isa(MR)) { if (T.isNull()) { if (const TypedRegion *TR = dyn_cast(MR)) -T = TR->getLocationType(); - else { -const SymbolicRegion *SR = cast(MR); -T = SR->getSymbol()->getType(); - } +T = TR->getLocationType()->getPointeeType(); + else if (const SymbolicRegion *SR = dyn_cast(MR)) +T = SR->getSymbol()->getType()->getPointeeType(); + else if (isa(MR)) +T = Ctx.VoidTy; +} +assert(!T.isNull() && "Unable to auto-detect binding type!"); +if (T->isVoidType()) { + // When trying to dereference a void pointer, read the first byte. + T = Ctx.CharTy; } MR = GetElementZeroRegion(cast(MR), T); } Modified: cfe/trunk/test/Analysis/ctor.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/ctor.mm?rev=314910&r1=314909&r2=314910&view=diff == --- cfe/trunk/test/Analysis/ctor.mm (original) +++ cfe/trunk/test/Analysis/ctor.mm Wed Oct 4 08:59:40 2017 @@ -199,7 +199,7 @@ namespace PODUninitialized { Inner p; }; - void testPOD() { + void testPOD(const POD &pp) { POD p; p.x = 1; POD p2 = p; // no-warning @@ -210,6 +210,15 @@ namespace PODUninitialized { // Use rvalues as well. clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}} +// Copy from symbolic references correctly. +POD p4 = pp; +// Make sure that p4.x contains a symbol after copy. +if (p4.x > 0) + clang_analyzer_eval(p4.x > 0); // expected-warning{{TRUE}} +// FIXME: Element region gets in the way, so these aren't the same symbols +// as they should be. +clang_analyzer_eval(pp.x == p4.x); // expected-warning{{UNKNOWN}} + PODWrapper w; w.p.y = 1; PODWrapper w2 = w; // no-warning Modified: cfe/trunk/test/Analysis/exercise-ps.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/exercise-ps.c?rev=314910&r1=314909&r2=314910&view=diff == --- cfe/trunk/test/Analysis/exercise-ps.c (original) +++ cfe/trunk/test/Analysis/exercise-ps.c Wed Oct 4 08:59:40 2017 @@ -21,3 +21,11 @@ static void f2(void *buf) { memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring library function 'memcpy' with type 'void *(void *, const void *}} \ // expected-note{{include the header or explicitly provide a declaration for 'memcpy'}} } + +// AllocaRegion is untyped. Void pointer isn't of much help either. Before +// realizing that the value is undefined, we need to somehow figure out +// what type of value do we expect. +void f3(void *dest) { + void *src = __builtin_alloca(5); + memcpy(dest, src, 1); // expected-warning{{2nd function call argument is a pointer to uninitialized value}} +} Modified: cfe/trunk/test/Analysis/gtest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/gtest.cpp?rev=314910&r1=314909&r2=314910&view=diff == --- cfe/trunk/test/Analysis/gtest.cpp (original) +++ cfe/trunk/test/Ana
r314975 - [analyzer] Fix leak false positives on stuff put in C++/ObjC initializer lists.
Author: dergachev Date: Thu Oct 5 01:43:32 2017 New Revision: 314975 URL: http://llvm.org/viewvc/llvm-project?rev=314975&view=rev Log: [analyzer] Fix leak false positives on stuff put in C++/ObjC initializer lists. The analyzer now realizes that C++ std::initializer_list objects and Objective-C boxed structure/array/dictionary expressions can potentially maintain a reference to the objects that were put into them. This avoids false memory leak posivites and a few other issues. This is a conservative behavior; for now, we do not model what actually happens to the objects after being passed into such initializer lists. rdar://problem/32918288 Differential Revision: https://reviews.llvm.org/D35216 Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/test/Analysis/initializer.cpp cfe/trunk/test/Analysis/objc-boxing.m cfe/trunk/test/Analysis/objc-for.m Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=314975&r1=314974&r2=314975&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Thu Oct 5 01:43:32 2017 @@ -827,6 +827,21 @@ void ExprEngine::VisitCXXBindTemporaryEx } } +namespace { +class CollectReachableSymbolsCallback final : public SymbolVisitor { + InvalidatedSymbols Symbols; + +public: + explicit CollectReachableSymbolsCallback(ProgramStateRef State) {} + const InvalidatedSymbols &getSymbols() const { return Symbols; } + + bool VisitSymbol(SymbolRef Sym) override { +Symbols.insert(Sym); +return true; + } +}; +} // end anonymous namespace + void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &DstTop) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), @@ -1103,8 +1118,29 @@ void ExprEngine::Visit(const Stmt *S, Ex SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, resultType, currBldrCtx->blockCount()); -ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result); -Bldr2.generateNode(S, N, state); +ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result); + +// Escape pointers passed into the list, unless it's an ObjC boxed +// expression which is not a boxable C structure. +if (!(isa(Ex) && + !cast(Ex)->getSubExpr() + ->getType()->isRecordType())) + for (auto Child : Ex->children()) { +assert(Child); + +SVal Val = State->getSVal(Child, LCtx); + +CollectReachableSymbolsCallback Scanner = +State->scanReachableSymbols( +Val); +const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols(); + +State = getCheckerManager().runCheckersForPointerEscape( +State, EscapedSymbols, +/*CallEvent*/ nullptr, PSK_EscapeOther, nullptr); + } + +Bldr2.generateNode(S, N, State); } getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); @@ -2237,21 +2273,6 @@ void ExprEngine::VisitAtomicExpr(const A getCheckerManager().runCheckersForPostStmt(Dst, AfterInvalidateSet, AE, *this); } -namespace { -class CollectReachableSymbolsCallback final : public SymbolVisitor { - InvalidatedSymbols Symbols; - -public: - CollectReachableSymbolsCallback(ProgramStateRef State) {} - const InvalidatedSymbols &getSymbols() const { return Symbols; } - - bool VisitSymbol(SymbolRef Sym) override { -Symbols.insert(Sym); -return true; - } -}; -} // end anonymous namespace - // A value escapes in three possible cases: // (1) We are binding to something that is not a memory region. // (2) We are binding to a MemrRegion that does not have stack storage. Modified: cfe/trunk/test/Analysis/initializer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/initializer.cpp?rev=314975&r1=314974&r2=314975&view=diff == --- cfe/trunk/test/Analysis/initializer.cpp (original) +++ cfe/trunk/test/Analysis/initializer.cpp Thu Oct 5 01:43:32 2017 @@ -1,7 +1,9 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s void clang_analyzer_eval(bool); +#include "Inputs/system-header-simulator-cxx.h" + class A { int x; public: @@ -204,3 +206,17 @@ struct C { const char(&f)[2]; }; } + +namespace CXX_init
r315298 - [analyzer] PthreadLockChecker: Add printState() method for self-debugging.
Author: dergachev Date: Tue Oct 10 04:49:09 2017 New Revision: 315298 URL: http://llvm.org/viewvc/llvm-project?rev=315298&view=rev Log: [analyzer] PthreadLockChecker: Add printState() method for self-debugging. This method injects additional information into program state dumps, describing states of mutexes tracked by the checker. Differential Revision: https://reviews.llvm.org/D37805 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp?rev=315298&r1=315297&r2=315298&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp Tue Oct 10 04:49:09 2017 @@ -81,6 +81,8 @@ class PthreadLockChecker public: void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; + void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const override; void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, bool isTryLock, enum LockingSemantics semantics) const; @@ -184,6 +186,39 @@ ProgramStateRef PthreadLockChecker::reso return state; } +void PthreadLockChecker::printState(raw_ostream &Out, ProgramStateRef State, +const char *NL, const char *Sep) const { + LockMapTy LM = State->get(); + if (!LM.isEmpty()) { +Out << Sep << "Mutex states:" << NL; +for (auto I : LM) { + I.first->dumpToStream(Out); + if (I.second.isLocked()) +Out << ": locked"; + else if (I.second.isUnlocked()) +Out << ": unlocked"; + else if (I.second.isDestroyed()) +Out << ": destroyed"; + else if (I.second.isUntouchedAndPossiblyDestroyed()) +Out << ": not tracked, possibly destroyed"; + else if (I.second.isUnlockedAndPossiblyDestroyed()) +Out << ": unlocked, possibly destroyed"; + Out << NL; +} + } + + LockSetTy LS = State->get(); + if (!LS.isEmpty()) { +Out << Sep << "Mutex lock order:" << NL; +for (auto I: LS) { + I->dumpToStream(Out); + Out << NL; +} + } + + // TODO: Dump destroyed mutex symbols? +} + void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, bool isTryLock, enum LockingSemantics semantics) const { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r315300 - [analyzer] MisusedMovedObject: Add printState() method for self-debugging.
Author: dergachev Date: Tue Oct 10 04:50:45 2017 New Revision: 315300 URL: http://llvm.org/viewvc/llvm-project?rev=315300&view=rev Log: [analyzer] MisusedMovedObject: Add printState() method for self-debugging. This method injects additional information into program state dumps, describing which objects have been moved from. Differential Revision: https://reviews.llvm.org/D31541 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp?rev=315300&r1=315299&r2=315300&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp Tue Oct 10 04:50:45 2017 @@ -56,6 +56,8 @@ public: ArrayRef ExplicitRegions, ArrayRef Regions, const LocationContext *LCtx, const CallEvent *Call) const; + void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const override; private: class MovedBugVisitor : public BugReporterVisitorImpl { @@ -476,6 +478,25 @@ ProgramStateRef MisusedMovedObjectChecke return State; } +void MisusedMovedObjectChecker::printState(raw_ostream &Out, + ProgramStateRef State, + const char *NL, + const char *Sep) const { + + TrackedRegionMapTy RS = State->get(); + + if (!RS.isEmpty()) { +Out << Sep << "Moved-from objects :" << NL; +for (auto I: RS) { + I.first->dumpToStream(Out); + if (I.second.isMoved()) +Out << ": moved"; + else +Out << ": moved and reported"; + Out << NL; +} + } +} void ento::registerMisusedMovedObjectChecker(CheckerManager &mgr) { mgr.registerChecker(); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r315301 - [analyzer] MisusedMovedObject: Fix state-resetting a base-class sub-object.
Author: dergachev Date: Tue Oct 10 04:55:56 2017 New Revision: 315301 URL: http://llvm.org/viewvc/llvm-project?rev=315301&view=rev Log: [analyzer] MisusedMovedObject: Fix state-resetting a base-class sub-object. If a method is resetting the state of an object that was moved from, it should be safe to use this object again. However if the method was defined in a parent class, but used in a child class, the reset didn't happen from the checker's perspective. Differential Revision: https://reviews.llvm.org/D31538 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp cfe/trunk/test/Analysis/MisusedMovedObject.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp?rev=315301&r1=315300&r2=315301&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp Tue Oct 10 04:55:56 2017 @@ -416,7 +416,14 @@ void MisusedMovedObjectChecker::checkPre return; if (isStateResetMethod(MethodDecl)) { -State = State->remove(ThisRegion); +// A state reset method resets the whole object, not only sub-object +// of a parent class in which it is defined. +const MemRegion *WholeObjectRegion = ThisRegion; +while (const CXXBaseObjectRegion *BR = + dyn_cast(WholeObjectRegion)) + WholeObjectRegion = BR->getSuperRegion(); + +State = State->remove(WholeObjectRegion); C.addTransition(State); return; } Modified: cfe/trunk/test/Analysis/MisusedMovedObject.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/MisusedMovedObject.cpp?rev=315301&r1=315300&r2=315301&view=diff == --- cfe/trunk/test/Analysis/MisusedMovedObject.cpp (original) +++ cfe/trunk/test/Analysis/MisusedMovedObject.cpp Tue Oct 10 04:55:56 2017 @@ -617,3 +617,11 @@ void subRegionMoveTest() { a.b.foo(); // no-warning } } + +class C: public A {}; +void resetSuperClass() { + C c; + C c1 = std::move(c); + c.clear(); + C c2 = c; // no-warning +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r315736 - [analyzer] RetainCount: Ignore annotations on user-made CFRetain wrappers.
Author: dergachev Date: Fri Oct 13 12:10:42 2017 New Revision: 315736 URL: http://llvm.org/viewvc/llvm-project?rev=315736&view=rev Log: [analyzer] RetainCount: Ignore annotations on user-made CFRetain wrappers. It is not uncommon for the users to make their own wrappers around CoreFoundation's CFRetain and CFRelease functions that are defensive against null references. In such cases CFRetain is often incorrectly marked as CF_RETURNS_RETAINED. Ignore said annotation and treat such wrappers similarly to the regular CFRetain. rdar://problem/31699502 Differential Revision: https://reviews.llvm.org/D38877 Added: cfe/trunk/test/Analysis/retain-release-safe.c Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=315736&r1=315735&r2=315736&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Fri Oct 13 12:10:42 2017 @@ -1170,6 +1170,11 @@ RetainSummaryManager::getFunctionSummary if (cocoa::isRefType(RetTy, "CF", FName)) { if (isRetain(FD, FName)) { S = getUnarySummary(FT, cfretain); + // CFRetain isn't supposed to be annotated. However, this may as well + // be a user-made "safe" CFRetain function that is incorrectly + // annotated as cf_returns_retained due to lack of better options. + // We want to ignore such annotation. + AllowAnnotations = false; } else if (isAutorelease(FD, FName)) { S = getUnarySummary(FT, cfautorelease); // The headers use cf_consumed, but we can fully model CFAutorelease Added: cfe/trunk/test/Analysis/retain-release-safe.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release-safe.c?rev=315736&view=auto == --- cfe/trunk/test/Analysis/retain-release-safe.c (added) +++ cfe/trunk/test/Analysis/retain-release-safe.c Fri Oct 13 12:10:42 2017 @@ -0,0 +1,72 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.RetainCount -verify %s + +#pragma clang arc_cf_code_audited begin +typedef const void * CFTypeRef; +extern CFTypeRef CFRetain(CFTypeRef cf); +extern void CFRelease(CFTypeRef cf); +#pragma clang arc_cf_code_audited end + +#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) +#define CF_CONSUMED __attribute__((cf_consumed)) + +extern CFTypeRef CFCreate() CF_RETURNS_RETAINED; + +// A "safe" variant of CFRetain that doesn't crash when a null pointer is +// retained. This is often defined by users in a similar manner. The +// CF_RETURNS_RETAINED annotation is misleading here, because the function +// is not supposed to return an object with a +1 retain count. Instead, it +// is supposed to return an object with +(N+1) retain count, where N is +// the original retain count of 'cf'. However, there is no good annotation +// to use in this case, and it is pointless to provide such annotation +// because the only use cases would be CFRetain and SafeCFRetain. +// So instead we teach the analyzer to be able to accept such code +// and ignore the misplaced annotation. +CFTypeRef SafeCFRetain(CFTypeRef cf) CF_RETURNS_RETAINED { + if (cf) { +return CFRetain(cf); + } + return cf; +} + +// A "safe" variant of CFRelease that doesn't crash when a null pointer is +// released. The CF_CONSUMED annotation seems reasonable here. +void SafeCFRelease(CFTypeRef CF_CONSUMED cf) { + if (cf) +CFRelease(cf); // no-warning (when inlined) +} + +void escape(CFTypeRef cf); + +void makeSureTestsWork() { + CFTypeRef cf = CFCreate(); + CFRelease(cf); + CFRelease(cf); // expected-warning{{Reference-counted object is used after it is released}} +} + +// Make sure we understand that the second SafeCFRetain doesn't return an +// object with +1 retain count, which we won't be able to release twice. +void falseOverrelease(CFTypeRef cf) { + SafeCFRetain(cf); + SafeCFRetain(cf); + SafeCFRelease(cf); + SafeCFRelease(cf); // no-warning after inlining this. +} + +// Regular CFRelease() should behave similarly. +void sameWithNormalRelease(CFTypeRef cf) { + SafeCFRetain(cf); + SafeCFRetain(cf); + CFRelease(cf); + CFRelease(cf); // no-warning +} + +// Make sure we understand that the second SafeCFRetain doesn't return an +// object with +1 retain count, which would no longer be owned by us after +// it escapes to escape() and released once. +void falseReleaseNotOwned(CFTypeRef cf) { + SafeCFRetain(cf); + SafeCFRetain(cf); + escape(cf); + SafeCFRelease(cf); + SafeCFRelease(cf); // no-warning after inlining this. +} ___ cfe-comm
r315742 - [analyzer] CStringChecker: pr34460: Avoid a crash when a cast is not modeled.
Author: dergachev Date: Fri Oct 13 13:11:00 2017 New Revision: 315742 URL: http://llvm.org/viewvc/llvm-project?rev=315742&view=rev Log: [analyzer] CStringChecker: pr34460: Avoid a crash when a cast is not modeled. The checker used to crash when a mempcpy's length argument is symbolic. In this case the cast from 'void *' to 'char *' failed because the respective ElementRegion that represents cast is hard to add on top of the existing ElementRegion that represents the offset to the last copied byte, while preseving a sane memory region structure. Additionally, a few test cases are added (to casts.c) which demonstrate problems caused by existing sloppy work we do with multi-layer ElementRegions. If said cast would be modeled properly in the future, these tests would need to be taken into account. Differential Revision: https://reviews.llvm.org/D38797 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp cfe/trunk/test/Analysis/bstring.cpp cfe/trunk/test/Analysis/casts.c Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=315742&r1=315741&r2=315742&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Fri Oct 13 13:11:00 2017 @@ -1050,31 +1050,22 @@ void CStringChecker::evalCopyCommon(Chec // If this is mempcpy, get the byte after the last byte copied and // bind the expr. if (IsMempcpy) { - loc::MemRegionVal destRegVal = destVal.castAs(); - - // Get the length to copy. - if (Optional lenValNonLoc = sizeVal.getAs()) { -// Get the byte after the last byte copied. -SValBuilder &SvalBuilder = C.getSValBuilder(); -ASTContext &Ctx = SvalBuilder.getContext(); -QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); -loc::MemRegionVal DestRegCharVal = SvalBuilder.evalCast(destRegVal, - CharPtrTy, Dest->getType()).castAs(); -SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add, - DestRegCharVal, - *lenValNonLoc, - Dest->getType()); - -// The byte after the last byte copied is the return value. -state = state->BindExpr(CE, LCtx, lastElement); - } else { -// If we don't know how much we copied, we can at least -// conjure a return value for later. -SVal result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, + // Get the byte after the last byte copied. + SValBuilder &SvalBuilder = C.getSValBuilder(); + ASTContext &Ctx = SvalBuilder.getContext(); + QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); + SVal DestRegCharVal = + SvalBuilder.evalCast(destVal, CharPtrTy, Dest->getType()); + SVal lastElement = C.getSValBuilder().evalBinOp( + state, BO_Add, DestRegCharVal, sizeVal, Dest->getType()); + // If we don't know how much we copied, we can at least + // conjure a return value for later. + if (lastElement.isUnknown()) +lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); -state = state->BindExpr(CE, LCtx, result); - } + // The byte after the last byte copied is the return value. + state = state->BindExpr(CE, LCtx, lastElement); } else { // All other copies return the destination buffer. // (Well, bcopy() has a void return type, but this won't hurt.) Modified: cfe/trunk/test/Analysis/bstring.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/bstring.cpp?rev=315742&r1=315741&r2=315742&view=diff == --- cfe/trunk/test/Analysis/bstring.cpp (original) +++ cfe/trunk/test/Analysis/bstring.cpp Fri Oct 13 13:11:00 2017 @@ -1,8 +1,35 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s +// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s +// RUN: %clang_analyze_cc1 -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s +// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s #include "Inputs/system-header-simulator-cxx.h" #include "Inputs/system-header-simulator-for-malloc.h" +// This provides us with four possible mempcpy() definitions. +// S
r315750 - [analyzer] pr28449: Fix support for various array initializers.
Author: dergachev Date: Fri Oct 13 13:54:56 2017 New Revision: 315750 URL: http://llvm.org/viewvc/llvm-project?rev=315750&view=rev Log: [analyzer] pr28449: Fix support for various array initializers. In some cases the analyzer didn't expect an array-type variable to be initialized with anything other than a string literal. The patch essentially removes the assertion, and ensures relatively sane behavior. There is a bigger problem with these initializers. Currently our memory model (RegionStore) is being ordered to initialize the array with a region that is assumed to be storing the initializer rvalue, and it guesses to copy the contents of that region to the array variable. However, it would make more sense for RegionStore to receive the correct initializer in the first place. This problem isn't addressed with this patch. rdar://problem/27248428 Differential Revision: https://reviews.llvm.org/D23963 Added: cfe/trunk/test/Analysis/compound-literals.c cfe/trunk/test/Analysis/objc-encode.m Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=315750&r1=315749&r2=315750&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Fri Oct 13 13:54:56 2017 @@ -2088,15 +2088,12 @@ RegionStoreManager::bindArray(RegionBind if (const ConstantArrayType* CAT = dyn_cast(AT)) Size = CAT->getSize().getZExtValue(); - // Check if the init expr is a string literal. + // Check if the init expr is a literal. If so, bind the rvalue instead. + // FIXME: It's not responsibility of the Store to transform this lvalue + // to rvalue. ExprEngine or maybe even CFG should do this before binding. if (Optional MRV = Init.getAs()) { -const StringRegion *S = cast(MRV->getRegion()); - -// Treat the string as a lazy compound value. -StoreRef store(B.asStore(), *this); -nonloc::LazyCompoundVal LCV = svalBuilder.makeLazyCompoundVal(store, S) -.castAs(); -return bindAggregate(B, R, LCV); +SVal V = getBinding(B.asStore(), *MRV, R->getValueType()); +return bindAggregate(B, R, V); } // Handle lazy compound values. Added: cfe/trunk/test/Analysis/compound-literals.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/compound-literals.c?rev=315750&view=auto == --- cfe/trunk/test/Analysis/compound-literals.c (added) +++ cfe/trunk/test/Analysis/compound-literals.c Fri Oct 13 13:54:56 2017 @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple=i386-apple-darwin10 -analyze -analyzer-checker=debug.ExprInspection -verify %s +void clang_analyzer_eval(int); + +// pr28449: Used to crash. +void foo(void) { + static const unsigned short array[] = (const unsigned short[]){0x0F00}; + // FIXME: Should be true. + clang_analyzer_eval(array[0] == 0x0F00); // expected-warning{{UNKNOWN}} +} Added: cfe/trunk/test/Analysis/objc-encode.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/objc-encode.m?rev=315750&view=auto == --- cfe/trunk/test/Analysis/objc-encode.m (added) +++ cfe/trunk/test/Analysis/objc-encode.m Fri Oct 13 13:54:56 2017 @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=debug.ExprInspection -verify %s +// expected-no-diagnostics + +void clang_analyzer_eval(int); + +// rdar://problem/34831581: Used to crash. +void foo(void) { + char buf1[] = @encode(int **); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r340975 - [CFG] [analyzer] Disable argument construction contexts for variadic functions.
Author: dergachev Date: Wed Aug 29 14:50:52 2018 New Revision: 340975 URL: http://llvm.org/viewvc/llvm-project?rev=340975&view=rev Log: [CFG] [analyzer] Disable argument construction contexts for variadic functions. The analyzer doesn't make use of them anyway and they seem to have pretty weird AST from time to time, so let's just skip them for now. Fixes pr37769. Differential Revision: https://reviews.llvm.org/D50824 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=340975&r1=340974&r2=340975&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Wed Aug 29 14:50:52 2018 @@ -2421,8 +2421,6 @@ CFGBlock *CFGBuilder::VisitCallExpr(Call if (!boundType.isNull()) calleeType = boundType; } - findConstructionContextsForArguments(C); - // If this is a call to a no-return function, this stops the block here. bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn(); @@ -2439,6 +2437,13 @@ CFGBlock *CFGBuilder::VisitCallExpr(Call bool OmitArguments = false; if (FunctionDecl *FD = C->getDirectCallee()) { +// TODO: Support construction contexts for variadic function arguments. +// These are a bit problematic and not very useful because passing +// C++ objects as C-style variadic arguments doesn't work in general +// (see [expr.call]). +if (!FD->isVariadic()) + findConstructionContextsForArguments(C); + if (FD->isNoReturn() || C->isBuiltinAssumeFalse(*Context)) NoReturn = true; if (FD->hasAttr()) Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=340975&r1=340974&r2=340975&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Wed Aug 29 14:50:52 2018 @@ -1028,3 +1028,18 @@ void testOperators() { C(1) + C(2); } } // namespace operators + +namespace variadic_function_arguments { +class C { + public: + C(int); +}; + +int variadic(...); + +// This code is quite exotic, so let's not test the CFG for it, +// but only make sure we don't crash. +void testCrashOnVariadicArgument() { + C c(variadic(0 ? c : 0)); // no-crash +} +} // namespace variadic_function_arguments ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r340977 - [CFG] [analyzer] Disable argument construction contexts for variadic functions.
Author: dergachev Date: Wed Aug 29 15:05:35 2018 New Revision: 340977 URL: http://llvm.org/viewvc/llvm-project?rev=340977&view=rev Log: [CFG] [analyzer] Disable argument construction contexts for variadic functions. The analyzer doesn't make use of them anyway and they seem to have pretty weird AST from time to time, so let's just skip them for now. Fixes a crash reported as pr37769. Differential Revision: https://reviews.llvm.org/D50855 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=340977&r1=340976&r2=340977&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Wed Aug 29 15:05:35 2018 @@ -734,10 +734,14 @@ private: /// /// If \p Result is provided, the new region will be bound to this expression /// instead of \p InitWithAdjustments. - ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State, -const LocationContext *LC, -const Expr *InitWithAdjustments, -const Expr *Result = nullptr); + /// + /// Returns the temporary region with adjustments into the optional + /// OutRegionWithAdjustments out-parameter if a new region was indeed needed, + /// otherwise sets it to nullptr. + ProgramStateRef createTemporaryRegionIfNeeded( + ProgramStateRef State, const LocationContext *LC, + const Expr *InitWithAdjustments, const Expr *Result = nullptr, + const SubRegion **OutRegionWithAdjustments = nullptr); /// Returns a region representing the first element of a (possibly /// multi-dimensional) array, for the purposes of element construction or Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=340977&r1=340976&r2=340977&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Wed Aug 29 15:05:35 2018 @@ -283,11 +283,10 @@ ProgramStateRef ExprEngine::getInitialSt return state; } -ProgramStateRef -ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, - const LocationContext *LC, - const Expr *InitWithAdjustments, - const Expr *Result) { +ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( +ProgramStateRef State, const LocationContext *LC, +const Expr *InitWithAdjustments, const Expr *Result, +const SubRegion **OutRegionWithAdjustments) { // FIXME: This function is a hack that works around the quirky AST // we're often having with respect to C++ temporaries. If only we modelled // the actual execution order of statements properly in the CFG, @@ -297,8 +296,11 @@ ExprEngine::createTemporaryRegionIfNeede if (!Result) { // If we don't have an explicit result expression, we're in "if needed" // mode. Only create a region if the current value is a NonLoc. -if (!InitValWithAdjustments.getAs()) +if (!InitValWithAdjustments.getAs()) { + if (OutRegionWithAdjustments) +*OutRegionWithAdjustments = nullptr; return State; +} Result = InitWithAdjustments; } else { // We need to create a region no matter what. For sanity, make sure we don't @@ -418,11 +420,17 @@ ExprEngine::createTemporaryRegionIfNeede // The result expression would now point to the correct sub-region of the // newly created temporary region. Do this last in order to getSVal of Init // correctly in case (Result == Init). - State = State->BindExpr(Result, LC, Reg); + if (Result->isGLValue()) { +State = State->BindExpr(Result, LC, Reg); + } else { +State = State->BindExpr(Result, LC, InitValWithAdjustments); + } // Notify checkers once for two bindLoc()s. State = processRegionChange(State, TR, LC); + if (OutRegionWithAdjustments) +*OutRegionWithAdjustments = cast(Reg.getAsRegion()); return State; } @@ -2532,8 +2540,12 @@ void ExprEngine::VisitMemberExpr(const M } // Handle regular struct fields / member variables. - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - SVal baseExprVal = state->getSVal(BaseExpr, LCtx); + const SubRegion *MR = nullptr; + state = createTemporaryRegionIfNeeded(state
r340982 - [analyzer] CFRetainReleaseChecker: Don't check C++ methods with the same name.
Author: dergachev Date: Wed Aug 29 15:39:20 2018 New Revision: 340982 URL: http://llvm.org/viewvc/llvm-project?rev=340982&view=rev Log: [analyzer] CFRetainReleaseChecker: Don't check C++ methods with the same name. Don't try to understand what's going on when there's a C++ method called eg. CFRetain(). Refactor the checker a bit, to use more modern APIs. Differential Revision: https://reviews.llvm.org/D50866 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp cfe/trunk/test/Analysis/retain-release.mm Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp?rev=340982&r1=340981&r2=340982&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp Wed Aug 29 15:39:20 2018 @@ -36,6 +36,7 @@ using namespace clang; using namespace ento; +using namespace llvm; namespace { class APIMisuse : public BugType { @@ -531,93 +532,59 @@ void CFNumberChecker::checkPreStmt(const //===--===// namespace { -class CFRetainReleaseChecker : public Checker< check::PreStmt > { - mutable std::unique_ptr BT; - mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease; +class CFRetainReleaseChecker : public Checker { + mutable APIMisuse BT{this, "null passed to CF memory management function"}; + CallDescription CFRetain{"CFRetain", 1}, + CFRelease{"CFRelease", 1}, + CFMakeCollectable{"CFMakeCollectable", 1}, + CFAutorelease{"CFAutorelease", 1}; public: - CFRetainReleaseChecker() - : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr), -Autorelease(nullptr) {} - void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; }; } // end anonymous namespace -void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, +void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - // If the CallExpr doesn't have exactly 1 argument just give up checking. - if (CE->getNumArgs() != 1) -return; - - ProgramStateRef state = C.getState(); - const FunctionDecl *FD = C.getCalleeDecl(CE); - if (!FD) + // TODO: Make this check part of CallDescription. + if (!Call.isGlobalCFunction()) return; - if (!BT) { -ASTContext &Ctx = C.getASTContext(); -Retain = &Ctx.Idents.get("CFRetain"); -Release = &Ctx.Idents.get("CFRelease"); -MakeCollectable = &Ctx.Idents.get("CFMakeCollectable"); -Autorelease = &Ctx.Idents.get("CFAutorelease"); -BT.reset(new APIMisuse( -this, "null passed to CF memory management function")); - } - // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease. - const IdentifierInfo *FuncII = FD->getIdentifier(); - if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable || -FuncII == Autorelease)) + if (!(Call.isCalled(CFRetain) || Call.isCalled(CFRelease) || +Call.isCalled(CFMakeCollectable) || Call.isCalled(CFAutorelease))) return; - // FIXME: The rest of this just checks that the argument is non-null. - // It should probably be refactored and combined with NonNullParamChecker. - // Get the argument's value. - const Expr *Arg = CE->getArg(0); - SVal ArgVal = C.getSVal(Arg); + SVal ArgVal = Call.getArgSVal(0); Optional DefArgVal = ArgVal.getAs(); if (!DefArgVal) return; - // Get a NULL value. - SValBuilder &svalBuilder = C.getSValBuilder(); - DefinedSVal zero = - svalBuilder.makeZeroVal(Arg->getType()).castAs(); - - // Make an expression asserting that they're equal. - DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal); - - // Are they equal? - ProgramStateRef stateTrue, stateFalse; - std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull); + // Is it null? + ProgramStateRef state = C.getState(); + ProgramStateRef stateNonNull, stateNull; + std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal); - if (stateTrue && !stateFalse) { -ExplodedNode *N = C.generateErrorNode(stateTrue); + if (!stateNonNull) { +ExplodedNode *N = C.generateErrorNode(stateNull); if (!N) return; -const char *description; -if (FuncII == Retain) - description = "Null pointer argument in call to CFRetain"; -else if (FuncII == Release) - description = "Null pointer argument in call to CFRelease"; -else if (FuncII == MakeCollectable) - description = "Null pointer argument in call to CFMakeCollectable"; -else if (FuncII == Autorelease) - description = "N
r340984 - [analyzer] Support modeling no-op BaseToDerived casts in ExprEngine.
Author: dergachev Date: Wed Aug 29 15:43:31 2018 New Revision: 340984 URL: http://llvm.org/viewvc/llvm-project?rev=340984&view=rev Log: [analyzer] Support modeling no-op BaseToDerived casts in ExprEngine. Introduce a new MemRegion sub-class, CXXDerivedObjectRegion, which is the opposite of CXXBaseObjectRegion, to represent such casts. Such region is a bit weird because it is by design bigger than its super-region. But it's not harmful when it is put on top of a SymbolicRegion that has unknown extent anyway. Offset computation for CXXDerivedObjectRegion and proper modeling of casts still remains to be implemented. Differential Revision: https://reviews.llvm.org/D51191 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def cfe/trunk/lib/StaticAnalyzer/Core/MemRegion.cpp cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp cfe/trunk/test/Analysis/casts.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h?rev=340984&r1=340983&r2=340984&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h Wed Aug 29 15:43:31 2018 @@ -122,7 +122,7 @@ public: /// Each region is a subregion of itself. virtual bool isSubRegionOf(const MemRegion *R) const; - const MemRegion *StripCasts(bool StripBaseCasts = true) const; + const MemRegion *StripCasts(bool StripBaseAndDerivedCasts = true) const; /// If this is a symbolic region, returns the region. Otherwise, /// goes up the base chain looking for the first symbolic base region. @@ -1176,6 +1176,47 @@ public: } }; +// CXXDerivedObjectRegion represents a derived-class object that surrounds +// a C++ object. It is identified by the derived class declaration and the +// region of its parent object. It is a bit counter-intuitive (but not otherwise +// unseen) that this region represents a larger segment of memory that its +// super-region. +class CXXDerivedObjectRegion : public TypedValueRegion { + friend class MemRegionManager; + + const CXXRecordDecl *DerivedD; + + CXXDerivedObjectRegion(const CXXRecordDecl *DerivedD, const SubRegion *SReg) + : TypedValueRegion(SReg, CXXDerivedObjectRegionKind), DerivedD(DerivedD) { +assert(DerivedD); +// In case of a concrete region, it should always be possible to model +// the base-to-derived cast by undoing a previous derived-to-base cast, +// otherwise the cast is most likely ill-formed. +assert(SReg->getSymbolicBase() && + "Should have unwrapped a base region instead!"); + } + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD, +const MemRegion *SReg); + +public: + const CXXRecordDecl *getDecl() const { return DerivedD; } + + QualType getValueType() const override; + + void dumpToStream(raw_ostream &os) const override; + + void Profile(llvm::FoldingSetNodeID &ID) const override; + + bool canPrintPrettyAsExpr() const override; + + void printPrettyAsExpr(raw_ostream &os) const override; + + static bool classof(const MemRegion *region) { +return region->getKind() == CXXDerivedObjectRegionKind; + } +}; + template const RegionTy* MemRegion::getAs() const { if (const auto *RT = dyn_cast(this)) @@ -1326,6 +1367,14 @@ public: baseReg->isVirtual()); } + /// Create a CXXDerivedObjectRegion with the given derived class for region + /// \p Super. This should not be used for casting an existing + /// CXXBaseObjectRegion back to the derived type; instead, CXXBaseObjectRegion + /// should be removed. + const CXXDerivedObjectRegion * + getCXXDerivedObjectRegion(const CXXRecordDecl *BaseClass, +const SubRegion *Super); + const FunctionCodeRegion *getFunctionCodeRegion(const NamedDecl *FD); const BlockCodeRegion *getBlockCodeRegion(const BlockDecl *BD, CanQualType locTy, Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def?rev=340984&r1=340983&r2=340984&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def Wed Aug 29 15:43:31 2018 @@ -68,6 +68,7 @@ ABSTRACT_REGION(SubRegion, MemRegion) ABSTRACT_REGION(TypedValueRegion, TypedRegion) REGION(CompoundLiteralRegion, Type
r340990 - [analyzer] Document that pointer arithmetic is not represented by SymExprs.
Author: dergachev Date: Wed Aug 29 15:57:52 2018 New Revision: 340990 URL: http://llvm.org/viewvc/llvm-project?rev=340990&view=rev Log: [analyzer] Document that pointer arithmetic is not represented by SymExprs. Add assertions to verify that. Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h?rev=340990&r1=340989&r2=340990&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h Wed Aug 29 15:57:52 2018 @@ -763,7 +763,9 @@ class SymbolicRegion : public SubRegion SymbolicRegion(const SymbolRef s, const MemSpaceRegion *sreg) : SubRegion(sreg, SymbolicRegionKind), sym(s) { -assert(s); +// Because pointer arithmetic is represented by ElementRegion layers, +// the base symbol here should not contain any arithmetic. +assert(s && isa(s)); assert(s->getType()->isAnyPointerType() || s->getType()->isReferenceType() || s->getType()->isBlockPointerType()); Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h?rev=340990&r1=340989&r2=340990&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h Wed Aug 29 15:57:52 2018 @@ -309,7 +309,10 @@ protected: BinarySymExpr(Kind k, BinaryOperator::Opcode op, QualType t) : SymExpr(k), Op(op), T(t) { assert(classof(this)); -assert(isValidTypeForSymbol(t)); +// Binary expressions are results of arithmetic. Pointer arithmetic is not +// handled by binary expressions, but it is instead handled by applying +// sub-regions to regions. +assert(isValidTypeForSymbol(t) && !Loc::isLocType(t)); } public: ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r341092 - [analyzer] InnerPointerChecker: Fix a segfault when checking symbolic strings.
Author: dergachev Date: Thu Aug 30 11:45:05 2018 New Revision: 341092 URL: http://llvm.org/viewvc/llvm-project?rev=341092&view=rev Log: [analyzer] InnerPointerChecker: Fix a segfault when checking symbolic strings. Return value of dyn_cast_or_null should be checked before use. Otherwise we may put a null pointer into the map as a key and eventually crash in checkDeadSymbols. Differential Revision: https://reviews.llvm.org/D51385 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp cfe/trunk/test/Analysis/inner-pointer.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp?rev=341092&r1=341091&r2=341092&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp Thu Aug 30 11:45:05 2018 @@ -211,8 +211,11 @@ void InnerPointerChecker::checkPostCall( ProgramStateRef State = C.getState(); if (const auto *ICall = dyn_cast(&Call)) { +// TODO: Do we need these to be typed? const auto *ObjRegion = dyn_cast_or_null( ICall->getCXXThisVal().getAsRegion()); +if (!ObjRegion) + return; if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) { SVal RawPtr = Call.getReturnValue(); Modified: cfe/trunk/test/Analysis/inner-pointer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inner-pointer.cpp?rev=341092&r1=341091&r2=341092&view=diff == --- cfe/trunk/test/Analysis/inner-pointer.cpp (original) +++ cfe/trunk/test/Analysis/inner-pointer.cpp Thu Aug 30 11:45:05 2018 @@ -424,3 +424,7 @@ void no_CXXRecordDecl() { *(void **)&b = c() + 1; *b = a; // no-crash } + +void checkReference(std::string &s) { + const char *c = s.c_str(); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r337769 - [analyzer] pr38273: Legalize Loc<>NonLoc comparison symbols.
Author: dergachev Date: Mon Jul 23 16:09:44 2018 New Revision: 337769 URL: http://llvm.org/viewvc/llvm-project?rev=337769&view=rev Log: [analyzer] pr38273: Legalize Loc<>NonLoc comparison symbols. Remove an assertion in RangeConstraintManager that expects such symbols to never appear, while admitting that the constraint manager doesn't yet handle them. Differential Revision: https://reviews.llvm.org/D49703 Modified: cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp cfe/trunk/test/Analysis/casts.c Modified: cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp?rev=337769&r1=337768&r2=337769&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp Mon Jul 23 16:09:44 2018 @@ -343,9 +343,11 @@ bool RangeConstraintManager::canReasonAb if (BinaryOperator::isEqualityOp(SSE->getOpcode()) || BinaryOperator::isRelationalOp(SSE->getOpcode())) { // We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc. +// We've recently started producing Loc <> NonLoc comparisons (that +// result from casts of one of the operands between eg. intptr_t and +// void *), but we can't reason about them yet. if (Loc::isLocType(SSE->getLHS()->getType())) { - assert(Loc::isLocType(SSE->getRHS()->getType())); - return true; + return Loc::isLocType(SSE->getRHS()->getType()); } } } Modified: cfe/trunk/test/Analysis/casts.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/casts.c?rev=337769&r1=337768&r2=337769&view=diff == --- cfe/trunk/test/Analysis/casts.c (original) +++ cfe/trunk/test/Analysis/casts.c Mon Jul 23 16:09:44 2018 @@ -171,3 +171,7 @@ void testCastVoidPtrToIntPtrThroughUIntT (*((int *)(&x))) = (int)(unsigned *)getVoidPtr(); *x = 1; // no-crash } + +void testLocNonLocSymbolAssume(int a, int *b) { + if ((int)b < a) {} +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r337776 - [analyzer] Add a no-crash to a recently added test.
Author: dergachev Date: Mon Jul 23 16:48:13 2018 New Revision: 337776 URL: http://llvm.org/viewvc/llvm-project?rev=337776&view=rev Log: [analyzer] Add a no-crash to a recently added test. No functional change intended. Modified: cfe/trunk/test/Analysis/casts.c Modified: cfe/trunk/test/Analysis/casts.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/casts.c?rev=337776&r1=337775&r2=337776&view=diff == --- cfe/trunk/test/Analysis/casts.c (original) +++ cfe/trunk/test/Analysis/casts.c Mon Jul 23 16:48:13 2018 @@ -173,5 +173,5 @@ void testCastVoidPtrToIntPtrThroughUIntT } void testLocNonLocSymbolAssume(int a, int *b) { - if ((int)b < a) {} + if ((int)b < a) {} // no-crash } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r338333 - [analyzer] CStringChecker: Remember to highlight the argument expression range.
Author: dergachev Date: Mon Jul 30 16:44:37 2018 New Revision: 338333 URL: http://llvm.org/viewvc/llvm-project?rev=338333&view=rev Log: [analyzer] CStringChecker: Remember to highlight the argument expression range. When emitting a bug report, it is important to highlight which argument of the call-expression is causing the problem. Before: warning: Null pointer argument in call to string comparison function strcmp(a, b); ^~~~ After: warning: Null pointer argument in call to string comparison function strcmp(a, b); ^ ~ Affects other output modes as well, not just text. Differential Revision: https://reviews.llvm.org/D50028 Added: cfe/trunk/test/Analysis/cstring-ranges.c Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=338333&r1=338332&r2=338333&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Mon Jul 30 16:44:37 2018 @@ -552,6 +552,7 @@ void CStringChecker::emitNullArgBug(Chec BuiltinBug *BT = static_cast(BT_Null.get()); auto Report = llvm::make_unique(*BT, WarningMsg, N); +Report->addRange(S->getSourceRange()); bugreporter::trackNullOrUndefValue(N, S, *Report); C.emitReport(std::move(Report)); } Added: cfe/trunk/test/Analysis/cstring-ranges.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cstring-ranges.c?rev=338333&view=auto == --- cfe/trunk/test/Analysis/cstring-ranges.c (added) +++ cfe/trunk/test/Analysis/cstring-ranges.c Mon Jul 30 16:44:37 2018 @@ -0,0 +1,15 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring -analyzer-output=text %s 2>&1 | FileCheck %s + +// This test verifies argument source range highlighting. +// Otherwise we've no idea which of the arguments is null. + +char *strcpy(char *, const char *); + +void foo() { + char *a = 0, *b = 0; + strcpy(a, b); +} + +// CHECK: warning: Null pointer argument in call to string copy function +// CHECK-NEXT: strcpy(a, b); +// CHECK-NEXT: ^ ~ ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r338339 - [analyzer] Rename test: cxx17-mandatory-elision.cpp -> copy-elision.cpp
Author: dergachev Date: Mon Jul 30 17:18:35 2018 New Revision: 338339 URL: http://llvm.org/viewvc/llvm-project?rev=338339&view=rev Log: [analyzer] Rename test: cxx17-mandatory-elision.cpp -> copy-elision.cpp It reflects its contents more accurately. No functional change intended. Added: cfe/trunk/test/Analysis/copy-elision.cpp Removed: cfe/trunk/test/Analysis/cxx17-mandatory-elision.cpp Added: cfe/trunk/test/Analysis/copy-elision.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/copy-elision.cpp?rev=338339&view=auto == --- cfe/trunk/test/Analysis/copy-elision.cpp (added) +++ cfe/trunk/test/Analysis/copy-elision.cpp Mon Jul 30 17:18:35 2018 @@ -0,0 +1,304 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG -verify %s + +// Copy elision always occurs in C++17, otherwise it's under +// an on-by-default flag. +#if __cplusplus >= 201703L + #define ELIDE 1 +#else + #ifndef NO_ELIDE_FLAG +#define ELIDE 1 + #endif +#endif + +void clang_analyzer_eval(bool); + +namespace variable_functional_cast_crash { + +struct A { + A(int) {} +}; + +void foo() { + A a = A(0); +} + +struct B { + A a; + B(): a(A(0)) {} +}; + +} // namespace variable_functional_cast_crash + + +namespace ctor_initializer { + +struct S { + int x, y, z; +}; + +struct T { + S s; + int w; + T(int w): s(), w(w) {} +}; + +class C { + T t; +public: + C() : t(T(4)) { +S s = {1, 2, 3}; +t.s = s; +// FIXME: Should be TRUE regardless of copy elision. +clang_analyzer_eval(t.w == 4); +#ifdef ELIDE +// expected-warning@-2{{TRUE}} +#else +// expected-warning@-4{{UNKNOWN}} +#endif + } +}; + + +struct A { + int x; + A(): x(0) {} + ~A() {} +}; + +struct B { + A a; + B() : a(A()) {} +}; + +void foo() { + B b; + clang_analyzer_eval(b.a.x == 0); // expected-warning{{TRUE}} +} + +} // namespace ctor_initializer + + +namespace elision_on_ternary_op_branches { +class C1 { + int x; +public: + C1(int x): x(x) {} + int getX() const { return x; } + ~C1(); +}; + +class C2 { + int x; + int y; +public: + C2(int x, int y): x(x), y(y) {} + int getX() const { return x; } + int getY() const { return y; } + ~C2(); +}; + +void foo(int coin) { + C1 c1 = coin ? C1(1) : C1(2); + if (coin) { +clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}} + } else { +clang_analyzer_eval(c1.getX() == 2); // expected-warning{{TRUE}} + } + C2 c2 = coin ? C2(3, 4) : C2(5, 6); + if (coin) { +clang_analyzer_eval(c2.getX() == 3); // expected-warning{{TRUE}} +clang_analyzer_eval(c2.getY() == 4); // expected-warning{{TRUE}} + } else { +clang_analyzer_eval(c2.getX() == 5); // expected-warning{{TRUE}} +clang_analyzer_eval(c2.getY() == 6); // expected-warning{{TRUE}} + } +} +} // namespace elision_on_ternary_op_branches + + +namespace address_vector_tests { + +template struct AddressVector { + T *buf[10]; + int len; + + AddressVector() : len(0) {} + + void push(T *t) { +buf[len] = t; +++len; + } +}; + +class ClassWithoutDestructor { + AddressVector &v; + +public: + ClassWithoutDestructor(AddressVector &v) : v(v) { +v.push(this); + } + + ClassWithoutDestructor(ClassWithoutDestructor &&c) : v(c.v) { v.push(this); } + ClassWithoutDestructor(const ClassWithoutDestructor &c) : v(c.v) { +v.push(this); + } +}; + +ClassWithoutDestructor make1(AddressVector &v) { + return ClassWithoutDestructor(v); +} +ClassWithoutDestructor make2(AddressVector &v) { + return make1(v); +} +ClassWithoutDestructor make3(AddressVector &v) { + return make2(v); +} + +void testMultipleReturns() { + AddressVector v; + ClassWithoutDestructor c = make3(v); + +#if ELIDE + clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[0] == &c); // expected-warning{{TRUE}} +#else + clang_analyzer_eval(v.len == 5); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[4] == &c); // expected-warning{{TRUE}} +#endif +} + +class ClassWithDestructor { + AddressVector &v; + +public: + ClassWithDestructor(AddressVector &v) : v(v) { +v.push(this); + } + + ClassWithDestructor(ClassWithDestructor &&c) : v(c.v) { v.push(this); } + ClassWithDestructor(const ClassW
r338420 - [analyzer] Don't try to simplify mixed Loc/NonLoc expressions.
Author: dergachev Date: Tue Jul 31 12:26:34 2018 New Revision: 338420 URL: http://llvm.org/viewvc/llvm-project?rev=338420&view=rev Log: [analyzer] Don't try to simplify mixed Loc/NonLoc expressions. This fix is similar to r337769 and addresses a regression caused by r337167. When an operation between a nonloc::LocAsInteger and a non-pointer symbol is performed, the LocAsInteger-specific part of information is lost. When the non-pointer symbol is collapsing into a constant, we cannot easily re-evaluate the result, because we need to recover the missing LocAsInteger-specific information (eg., integer type, or the very fact that this pointer was at some point converted to an integer). Add one more defensive check to prevent crashes on trying to simplify a SymSymExpr with different Loc-ness of operands. Differential Revision: Modified: cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp cfe/trunk/test/Analysis/casts.c Modified: cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp?rev=338420&r1=338419&r2=338420&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp Tue Jul 31 12:26:34 2018 @@ -1291,6 +1291,17 @@ SVal SimpleSValBuilder::simplifySVal(Pro if (I != Cached.end()) return I->second; + // For now don't try to simplify mixed Loc/NonLoc expressions + // because they often appear from LocAsInteger operations + // and we don't know how to combine a LocAsInteger + // with a concrete value. + if (Loc::isLocType(S->getLHS()->getType()) != + Loc::isLocType(S->getRHS()->getType())) { +SVal V = SVB.makeSymbolVal(S); +Cached[S] = V; +return V; + } + SVal LHS = Visit(S->getLHS()); SVal RHS = Visit(S->getRHS()); if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS)) { Modified: cfe/trunk/test/Analysis/casts.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/casts.c?rev=338420&r1=338419&r2=338420&view=diff == --- cfe/trunk/test/Analysis/casts.c (original) +++ cfe/trunk/test/Analysis/casts.c Tue Jul 31 12:26:34 2018 @@ -175,3 +175,10 @@ void testCastVoidPtrToIntPtrThroughUIntT void testLocNonLocSymbolAssume(int a, int *b) { if ((int)b < a) {} // no-crash } + +void testLocNonLocSymbolRemainder(int a, int *b) { + int c = ((int)b) % a; + if (a == 1) { +c += 1; + } +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r338422 - [analyzer] Reuse some code in simplifySVal().
Author: dergachev Date: Tue Jul 31 12:29:25 2018 New Revision: 338422 URL: http://llvm.org/viewvc/llvm-project?rev=338422&view=rev Log: [analyzer] Reuse some code in simplifySVal(). No functional change intended. Differential Revision: https://reviews.llvm.org/D49826 Modified: cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp?rev=338422&r1=338421&r2=338422&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp Tue Jul 31 12:29:25 2018 @@ -1236,11 +1236,21 @@ SVal SimpleSValBuilder::simplifySVal(Pro return Sym == Val.getAsSymbol(); } +SVal cache(SymbolRef Sym, SVal V) { + Cached[Sym] = V; + return V; +} + +SVal skip(SymbolRef Sym) { + return cache(Sym, SVB.makeSymbolVal(Sym)); +} + public: Simplifier(ProgramStateRef State) : State(State), SVB(State->getStateManager().getSValBuilder()) {} SVal VisitSymbolData(const SymbolData *S) { + // No cache here. if (const llvm::APSInt *I = SVB.getKnownValue(State, SVB.makeSymbolVal(S))) return Loc::isLocType(S->getType()) ? (SVal)SVB.makeIntLocVal(*I) @@ -1257,11 +1267,9 @@ SVal SimpleSValBuilder::simplifySVal(Pro return I->second; SVal LHS = Visit(S->getLHS()); - if (isUnchanged(S->getLHS(), LHS)) { -SVal V = SVB.makeSymbolVal(S); -Cached[S] = V; -return V; - } + if (isUnchanged(S->getLHS(), LHS)) +return skip(S); + SVal RHS; // By looking at the APSInt in the right-hand side of S, we cannot // figure out if it should be treated as a Loc or as a NonLoc. @@ -1281,9 +1289,8 @@ SVal SimpleSValBuilder::simplifySVal(Pro RHS = SVB.makeIntVal(S->getRHS()); } - SVal V = SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()); - Cached[S] = V; - return V; + return cache( + S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType())); } SVal VisitSymSymExpr(const SymSymExpr *S) { @@ -1296,22 +1303,16 @@ SVal SimpleSValBuilder::simplifySVal(Pro // and we don't know how to combine a LocAsInteger // with a concrete value. if (Loc::isLocType(S->getLHS()->getType()) != - Loc::isLocType(S->getRHS()->getType())) { -SVal V = SVB.makeSymbolVal(S); -Cached[S] = V; -return V; - } + Loc::isLocType(S->getRHS()->getType())) +return skip(S); SVal LHS = Visit(S->getLHS()); SVal RHS = Visit(S->getRHS()); - if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS)) { -SVal V = SVB.makeSymbolVal(S); -Cached[S] = V; -return V; - } - SVal V = SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()); - Cached[S] = V; - return V; + if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS)) +return skip(S); + + return cache( + S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType())); } SVal VisitSymExpr(SymbolRef S) { return nonloc::SymbolVal(S); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r338425 - [CFG] [analyzer] Add stubs for constructor and message argument constructors.
Author: dergachev Date: Tue Jul 31 12:39:37 2018 New Revision: 338425 URL: http://llvm.org/viewvc/llvm-project?rev=338425&view=rev Log: [CFG] [analyzer] Add stubs for constructor and message argument constructors. CFG now correctly identifies construction context for temporaries constructed for the purpose of passing into a function as an argument. Such context is still not fully implemented because the information it provides is not rich enough: it doens't contain information about argument index. It will be addresssed later. This patch is an extension of r330377 to C++ construct-expressions and Objective-C message expressions which aren't call-expressions but require similar handling. C++ new-expressions with placement arguments still remain to be handled. Differential Revision: https://reviews.llvm.org/D49826 Added: cfe/trunk/test/Analysis/cfg-rich-constructors.mm cfe/trunk/test/Analysis/temporaries.mm Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/lib/Analysis/ConstructionContext.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=338425&r1=338424&r2=338425&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Tue Jul 31 12:39:37 2018 @@ -569,6 +569,7 @@ private: CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S); CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); + CFGBlock *VisitObjCMessageExpr(ObjCMessageExpr *E, AddStmtChoice asc); CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E); CFGBlock *VisitReturnStmt(ReturnStmt *R); CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S); @@ -683,6 +684,27 @@ private: void findConstructionContexts(const ConstructionContextLayer *Layer, Stmt *Child); + // Scan all arguments of a call expression for a construction context. + // These sorts of call expressions don't have a common superclass, + // hence strict duck-typing. + template ::value || +std::is_same::value || +std::is_same::value>> + void findConstructionContextsForArguments(CallLikeExpr *E) { +// A stub for the code that'll eventually be used for finding construction +// contexts for constructors of C++ object-type arguments passed into +// call-like expression E. +// FIXME: Once actually implemented, this construction context layer should +// include the index of the argument as well. +for (auto Arg : E->arguments()) + if (Arg->getType()->getAsCXXRecordDecl() && !Arg->isGLValue()) +findConstructionContexts( +ConstructionContextLayer::create(cfg->getBumpVectorContext(), E), +Arg); + } + // Unset the construction context after consuming it. This is done immediately // after adding the CFGConstructor or CFGCXXRecordTypedCall element, so // there's no need to do this manually in every Visit... function. @@ -2101,6 +2123,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, Ad case Stmt::ObjCForCollectionStmtClass: return VisitObjCForCollectionStmt(cast(S)); +case Stmt::ObjCMessageExprClass: + return VisitObjCMessageExpr(cast(S), asc); + case Stmt::OpaqueValueExprClass: return Block; @@ -2383,12 +2408,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(Call if (!boundType.isNull()) calleeType = boundType; } - // FIXME: Once actually implemented, this construction context layer should - // include the number of the argument as well. - for (auto Arg: C->arguments()) { -findConstructionContexts( -ConstructionContextLayer::create(cfg->getBumpVectorContext(), C), Arg); - } + findConstructionContextsForArguments(C); // If this is a call to a no-return function, this stops the block here. bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn(); @@ -3580,6 +3600,16 @@ CFGBlock *CFGBuilder::VisitObjCAtThrowSt return VisitStmt(S, AddStmtChoice::AlwaysAdd); } +CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME, + AddStmtChoice asc) { + findConstructionContextsForArguments(ME); + + autoCreateBlock(); + appendStmt(Block, ME); + + return VisitChildren(ME); +} + CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) { // If we were in the middle of a block we stop processing that block. if (badCFG) @@ -4244,6 +4274,11 @@ CFGBlock *CFGBuilder::VisitCXXBindTempor CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc) { + // If the constructor takes objects as arguments by value, we need to properly + // construct these objects. Construction contexts we find here aren't for the +
r338426 - [CFG] [analyzer] Add construction contexts for returning C++ objects in ObjC++.
Author: dergachev Date: Tue Jul 31 12:46:14 2018 New Revision: 338426 URL: http://llvm.org/viewvc/llvm-project?rev=338426&view=rev Log: [CFG] [analyzer] Add construction contexts for returning C++ objects in ObjC++. Like any normal funciton, Objective-C message can return a C++ object in Objective-C++. Such object would require a construction context. This patch, therefore, is an extension of r327343 onto Objective-C++. Differential Revision: https://reviews.llvm.org/D48608 Added: cfe/trunk/test/Analysis/lifetime-extension.mm Modified: cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.mm Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=338426&r1=338425&r2=338426&view=diff == --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Tue Jul 31 12:46:14 2018 @@ -15,9 +15,10 @@ #ifndef LLVM_CLANG_ANALYSIS_CFG_H #define LLVM_CLANG_ANALYSIS_CFG_H -#include "clang/AST/ExprCXX.h" #include "clang/Analysis/Support/BumpVector.h" #include "clang/Analysis/ConstructionContext.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/GraphTraits.h" @@ -179,15 +180,18 @@ class CFGCXXRecordTypedCall : public CFG public: /// Returns true when call expression \p CE needs to be represented /// by CFGCXXRecordTypedCall, as opposed to a regular CFGStmt. - static bool isCXXRecordTypedCall(CallExpr *CE, const ASTContext &ACtx) { -return CE->getCallReturnType(ACtx).getCanonicalType()->getAsCXXRecordDecl(); + static bool isCXXRecordTypedCall(Expr *E) { +assert(isa(E) || isa(E)); +// There is no such thing as reference-type expression. If the function +// returns a reference, it'll return the respective lvalue or xvalue +// instead, and we're only interested in objects. +return !E->isGLValue() && + E->getType().getCanonicalType()->getAsCXXRecordDecl(); } - explicit CFGCXXRecordTypedCall(CallExpr *CE, const ConstructionContext *C) - : CFGStmt(CE, CXXRecordTypedCall) { -// FIXME: This is not protected against squeezing a non-record-typed-call -// into the constructor. An assertion would require passing an ASTContext -// which would mean paying for something we don't use. + explicit CFGCXXRecordTypedCall(Expr *E, const ConstructionContext *C) + : CFGStmt(E, CXXRecordTypedCall) { +assert(isCXXRecordTypedCall(E)); assert(C && (isa(C) || // These are possible in C++17 due to mandatory copy elision. isa(C) || @@ -874,10 +878,10 @@ public: Elements.push_back(CFGConstructor(CE, CC), C); } - void appendCXXRecordTypedCall(CallExpr *CE, + void appendCXXRecordTypedCall(Expr *E, const ConstructionContext *CC, BumpVectorContext &C) { -Elements.push_back(CFGCXXRecordTypedCall(CE, CC), C); +Elements.push_back(CFGCXXRecordTypedCall(E, CC), C); } void appendInitializer(CXXCtorInitializer *initializer, Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=338426&r1=338425&r2=338426&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Tue Jul 31 12:46:14 2018 @@ -743,6 +743,19 @@ private: void addLocalScopeAndDtors(Stmt *S); + const ConstructionContext *retrieveAndCleanupConstructionContext(Expr *E) { +if (!BuildOpts.AddRichCXXConstructors) + return nullptr; + +const ConstructionContextLayer *Layer = ConstructionContextMap.lookup(E); +if (!Layer) + return nullptr; + +cleanupConstructionContext(E); +return ConstructionContext::createFromLayers(cfg->getBumpVectorContext(), + Layer); + } + // Interface to CFGBlock - adding CFGElements. void appendStmt(CFGBlock *B, const Stmt *S) { @@ -755,16 +768,10 @@ private: } void appendConstructor(CFGBlock *B, CXXConstructExpr *CE) { -if (BuildOpts.AddRichCXXConstructors) { - if (const ConstructionContextLayer *Layer = - ConstructionContextMap.lookup(CE)) { -cleanupConstructionContext(CE); -if (const auto *CC = ConstructionContext::createFromLayers( -cfg->getBumpVectorContext(), Layer)) { - B->appendConstructor(CE, CC, cfg->getBumpVectorContext()); - return; -} - } +if (const ConstructionContext *CC = +retrieveAndCleanupConstructionContext(CE)) { + B->appendConstructor(CE, CC, cfg->getBumpVectorContext()); + return; } // No valid
r338436 - [CFG] [analyzer] Implement function argument construction contexts.
Author: dergachev Date: Tue Jul 31 13:45:53 2018 New Revision: 338436 URL: http://llvm.org/viewvc/llvm-project?rev=338436&view=rev Log: [CFG] [analyzer] Implement function argument construction contexts. In r330377 and r338425 we have already identified what constitutes function argument constructors and added stubs in order to prevent confusing them with other temporary object constructors. Now we implement a ConstructionContext sub-class to carry all the necessary information about the construction site, namely call expression and argument index. On the analyzer side, the patch interacts with the recently implemented pre-C++17 copy elision support in an interesting manner. If on the CFG side we didn't find a construction context for the elidable constructor, we build the CFG as if the elidable constructor is not elided, and the non-elided constructor within it is a simple temporary. But the same problem may occur in the analyzer: if the elidable constructor has a construction context but the analyzer doesn't implement such context yet, the analyzer should also try to skip copy elision and still inline the non-elided temporary constructor. This was implemented by adding a "roll back" mechanism: when elision fails, roll back the changes and proceed as if it's a simple temporary. The approach is wonky, but i'm fine with that as long as it's merely a defensive mechanism that should eventually go away once all construction contexts become supported. Differential Revision: https://reviews.llvm.org/D48681. Modified: cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/include/clang/Analysis/ConstructionContext.h cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/lib/Analysis/ConstructionContext.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.mm Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=338436&r1=338435&r2=338436&view=diff == --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Tue Jul 31 13:45:53 2018 @@ -196,7 +196,8 @@ public: // These are possible in C++17 due to mandatory copy elision. isa(C) || isa(C) || - isa(C))); + isa(C) || + isa(C))); Data2.setPointer(const_cast(C)); } Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ConstructionContext.h?rev=338436&r1=338435&r2=338436&view=diff == --- cfe/trunk/include/clang/Analysis/ConstructionContext.h (original) +++ cfe/trunk/include/clang/Analysis/ConstructionContext.h Tue Jul 31 13:45:53 2018 @@ -41,6 +41,12 @@ private: /// new-expression triggers construction of the newly allocated object(s). TriggerTy Trigger; + /// If a single trigger statement triggers multiple constructors, they are + /// usually being enumerated. This covers function argument constructors + /// triggered by a call-expression and items in an initializer list triggered + /// by an init-list-expression. + unsigned Index; + /// Sometimes a single trigger is not enough to describe the construction /// site. In this case we'd have a chain of "partial" construction context /// layers. @@ -55,13 +61,13 @@ private: /// Not all of these are currently supported. const ConstructionContextLayer *Parent = nullptr; - ConstructionContextLayer(TriggerTy Trigger, - const ConstructionContextLayer *Parent) - : Trigger(Trigger), Parent(Parent) {} + ConstructionContextLayer(TriggerTy Trigger, unsigned Index, + const ConstructionContextLayer *Parent) + : Trigger(Trigger), Index(Index), Parent(Parent) {} public: static const ConstructionContextLayer * - create(BumpVectorContext &C, TriggerTy Trigger, + create(BumpVectorContext &C, TriggerTy Trigger, unsigned Index = 0, const ConstructionContextLayer *Parent = nullptr); const ConstructionContextLayer *getParent() const { return Parent; } @@ -75,11 +81,13 @@ public: return Trigger.dyn_cast(); } + unsigned getIndex() const { return Index; } + /// Returns true if these layers are equal as individual layers, even if /// their parents are different. bool isSameLayer(const ConstructionContextLayer *Other) const { assert(Other); -return (Trigger == Other->Trigger); +return (Trigger == Other->Trigger && Index == Other->Index); } /// See if Other is a proper initial segment of this construction context @@ -114,7 +122,8 @@ public: SimpleReturnedValueKind, CXX17ElidedCopyReturnedValueKind, RETURNED_
r338439 - [CFG] [analyzer] NFC: Enumerate construction context layer kinds.
Author: dergachev Date: Tue Jul 31 14:12:42 2018 New Revision: 338439 URL: http://llvm.org/viewvc/llvm-project?rev=338439&view=rev Log: [CFG] [analyzer] NFC: Enumerate construction context layer kinds. This is a refactoring patch; no functional change intended. The common part of ConstructionContextLayer and ConstructedObjectKey is factored out into a new structure, ConstructionContextItem. Various sub-kinds of ConstructionContextItem are enumerated in order to provide richer information about construction contexts. Differential Revision: https://reviews.llvm.org/D49210. Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/lib/Analysis/ConstructionContext.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ConstructionContext.h?rev=338439&r1=338438&r2=338439&view=diff == --- cfe/trunk/include/clang/Analysis/ConstructionContext.h (original) +++ cfe/trunk/include/clang/Analysis/ConstructionContext.h Tue Jul 31 14:12:42 2018 @@ -22,74 +22,193 @@ namespace clang { -/// Construction context is a linked list of multiple layers. Layers are -/// created gradually while traversing the AST, and layers that represent -/// the outmost AST nodes are built first, while the node that immediately -/// contains the constructor would be built last and capture the previous -/// layers as its parents. Construction context captures the last layer -/// (which has links to the previous layers) and classifies the seemingly -/// arbitrary chain of layers into one of the possible ways of constructing -/// an object in C++ for user-friendly experience. -class ConstructionContextLayer { +/// Represents a single point (AST node) in the program that requires attention +/// during construction of an object. ConstructionContext would be represented +/// as a list of such items. +class ConstructionContextItem { public: - typedef llvm::PointerUnion TriggerTy; + enum ItemKind { +VariableKind, +NewAllocatorKind, +ReturnKind, +MaterializationKind, +TemporaryDestructorKind, +ElidedDestructorKind, +ElidableConstructorKind, +ArgumentKind, +STATEMENT_WITH_INDEX_KIND_BEGIN=ArgumentKind, +STATEMENT_WITH_INDEX_KIND_END=ArgumentKind, +STATEMENT_KIND_BEGIN = VariableKind, +STATEMENT_KIND_END = ArgumentKind, +InitializerKind, +INITIALIZER_KIND_BEGIN=InitializerKind, +INITIALIZER_KIND_END=InitializerKind + }; + + LLVM_DUMP_METHOD static StringRef getKindAsString(ItemKind K) { +switch (K) { + case VariableKind:return "construct into local variable"; + case NewAllocatorKind:return "construct into new-allocator"; + case ReturnKind: return "construct into return address"; + case MaterializationKind: return "materialize temporary"; + case TemporaryDestructorKind: return "destroy temporary"; + case ElidedDestructorKind:return "elide destructor"; + case ElidableConstructorKind: return "elide constructor"; + case ArgumentKind:return "construct into argument"; + case InitializerKind: return "construct into member variable"; +}; + } private: + const void *const Data; + const ItemKind Kind; + const unsigned Index = 0; + + bool hasStatement() const { +return Kind >= STATEMENT_KIND_BEGIN && + Kind <= STATEMENT_KIND_END; + } + + bool hasIndex() const { +return Kind >= STATEMENT_WITH_INDEX_KIND_BEGIN && + Kind >= STATEMENT_WITH_INDEX_KIND_END; + } + + bool hasInitializer() const { +return Kind >= INITIALIZER_KIND_BEGIN && + Kind <= INITIALIZER_KIND_END; + } + +public: + // ConstructionContextItem should be simple enough so that it was easy to + // re-construct it from the AST node it captures. For that reason we provide + // simple implicit conversions from all sorts of supported AST nodes. + ConstructionContextItem(const DeclStmt *DS) + : Data(DS), Kind(VariableKind) {} + + ConstructionContextItem(const CXXNewExpr *NE) + : Data(NE), Kind(NewAllocatorKind) {} + + ConstructionContextItem(const ReturnStmt *RS) + : Data(RS), Kind(ReturnKind) {} + + ConstructionContextItem(const MaterializeTemporaryExpr *MTE) + : Data(MTE), Kind(MaterializationKind) {} + + ConstructionContextItem(const CXXBindTemporaryExpr *BTE, + bool IsElided = false) + : Data(BTE), +Kind(IsElided ? ElidedDestructorKind : TemporaryDestructorKind) {} + + ConstructionContextItem(const CXXConstructExpr *CE) + : Data(CE), Kind(ElidableConstructorKind) {} + + ConstructionContextItem(const CallExpr *CE, unsigned Index) + : Data(CE), Kin
r338441 - [analyzer] Fix eliding the same destructor twice due to buggy default arguments.
Author: dergachev Date: Tue Jul 31 14:17:40 2018 New Revision: 338441 URL: http://llvm.org/viewvc/llvm-project?rev=338441&view=rev Log: [analyzer] Fix eliding the same destructor twice due to buggy default arguments. Because of incomplete support for CXXDefaultArgExpr, we cannot yet commit to asserting that the same destructor won't be elided twice. Suppress the assertion failure for now. Proper support is still an open problem. Differential Revision: https://reviews.llvm.org/D49213 Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=338441&r1=338440&r2=338441&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Jul 31 14:17:40 2018 @@ -460,7 +460,8 @@ ProgramStateRef ExprEngine::elideDestruc const CXXBindTemporaryExpr *BTE, const LocationContext *LC) { ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC); - assert(!State->contains(Key)); + // FIXME: Currently the state might already contain the marker due to + // incorrect handling of temporaries bound to default parameters. return State->set(Key, UnknownVal()); } Modified: cfe/trunk/test/Analysis/temporaries.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temporaries.cpp?rev=338441&r1=338440&r2=338441&view=diff == --- cfe/trunk/test/Analysis/temporaries.cpp (original) +++ cfe/trunk/test/Analysis/temporaries.cpp Tue Jul 31 14:17:40 2018 @@ -458,6 +458,21 @@ namespace destructors { #endif // TEMPORARY_DTORS } +namespace default_param_elided_destructors { +struct a { + ~a(); +}; +struct F { + a d; + F(char *, a = a()); +}; +void g() { + char h[1]; + for (int i = 0;;) +F j(i ? j : h); +} +} // namespace default_param_elided_destructors + void testStaticMaterializeTemporaryExpr() { static const Trivial &ref = getTrivial(); clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r338474 - [analyzer] CallEvent: Add helper methods for obtaining the callee stack frame.
Author: dergachev Date: Tue Jul 31 18:58:15 2018 New Revision: 338474 URL: http://llvm.org/viewvc/llvm-project?rev=338474&view=rev Log: [analyzer] CallEvent: Add helper methods for obtaining the callee stack frame. Newly added methods allow reasoning about the stack frame of the call (as opposed to the stack frame on which the call was made, which was always available) - obtain the stack frame context, obtain parameter regions - even if the call is not going to be (or was not) inlined, i.e. even if the analysis has never actually entered the stack frame. Differential Revision: https://reviews.llvm.org/D49715 Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ConstructionContext.h?rev=338474&r1=338473&r2=338474&view=diff == --- cfe/trunk/include/clang/Analysis/ConstructionContext.h (original) +++ cfe/trunk/include/clang/Analysis/ConstructionContext.h Tue Jul 31 18:58:15 2018 @@ -112,6 +112,13 @@ public: ConstructionContextItem(const ObjCMessageExpr *ME, unsigned Index) : Data(ME), Kind(ArgumentKind), Index(Index) {} + // A polymorphic version of the previous calls with dynamic type check. + ConstructionContextItem(const Expr *E, unsigned Index) + : Data(E), Kind(ArgumentKind), Index(Index) { +assert(isa(E) || isa(E) || + isa(E)); + } + ConstructionContextItem(const CXXCtorInitializer *Init) : Data(Init), Kind(InitializerKind), Index(0) {} Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h?rev=338474&r1=338473&r2=338474&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h Tue Jul 31 18:58:15 2018 @@ -29,6 +29,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" @@ -404,6 +405,46 @@ public: /// \p D must not be null. static bool isVariadic(const Decl *D); + /// Returns AnalysisDeclContext for the callee stack frame. + /// Currently may fail; returns null on failure. + AnalysisDeclContext *getCalleeAnalysisDeclContext() const; + + /// Returns the callee stack frame. That stack frame will only be entered + /// during analysis if the call is inlined, but it may still be useful + /// in intermediate calculations even if the call isn't inlined. + /// May fail; returns null on failure. + const StackFrameContext *getCalleeStackFrame() const; + + /// Returns memory location for a parameter variable within the callee stack + /// frame. May fail; returns null on failure. + const VarRegion *getParameterLocation(unsigned Index) const; + + /// Returns true if on the current path, the argument was constructed by + /// calling a C++ constructor over it. This is an internal detail of the + /// analysis which doesn't necessarily represent the program semantics: + /// if we are supposed to construct an argument directly, we may still + /// not do that because we don't know how (i.e., construction context is + /// unavailable in the CFG or not supported by the analyzer). + bool isArgumentConstructedDirectly(unsigned Index) const { +// This assumes that the object was not yet removed from the state. +return ExprEngine::getObjectUnderConstruction( +getState(), {getOriginExpr(), Index}, getCalleeStackFrame()).hasValue(); + } + + /// Some calls have parameter numbering mismatched from argument numbering. + /// This function converts an argument index to the corresponding + /// parameter index. Returns None is the argument doesn't correspond + /// to any parameter variable. + Optional getAdjustedParameterIndex(unsigned ArgumentIndex) const { +if (dyn_cast_or_null(getOriginExpr()) && +dyn_cast_or_null(getDecl())) { + // For member operator calls argument 0 on the expression corresponds + // to implicit this-parameter on the declaration. + return (ArgumentIndex > 0) ? Optional(ArgumentIndex - 1) : None; +} +return ArgumentIndex; + } + // Iterator access to formal parameters and their types. private: struct GetTyp
r324660 - [analyzer] Self-debug: Dump environment frame-by-frame.
Author: dergachev Date: Thu Feb 8 14:24:38 2018 New Revision: 324660 URL: http://llvm.org/viewvc/llvm-project?rev=324660&view=rev Log: [analyzer] Self-debug: Dump environment frame-by-frame. It makes it easier to discriminate between values of similar expressions in different stack frames. It also makes the separate backtrace section in ExplodedGraph dumps redundant. Differential Revision: https://reviews.llvm.org/D42552 Modified: cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp cfe/trunk/test/Analysis/crash-trace.c cfe/trunk/test/Analysis/expr-inspection.c Modified: cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h?rev=324660&r1=324659&r2=324660&view=diff == --- cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h (original) +++ cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h Thu Feb 8 14:24:38 2018 @@ -265,7 +265,11 @@ public: virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; - void dumpStack(raw_ostream &OS, StringRef Indent = "") const; + void dumpStack( + raw_ostream &OS, StringRef Indent = "", const char *NL = "\n", + const char *Sep = "", + std::function printMoreInfoPerContext = + [](const LocationContext *) {}) const; void dumpStack() const; public: Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h?rev=324660&r1=324659&r2=324660&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h Thu Feb 8 14:24:38 2018 @@ -92,12 +92,9 @@ public: bool operator==(const Environment& RHS) const { return ExprBindings == RHS.ExprBindings; } - - void print(raw_ostream &Out, const char *NL, const char *Sep) const; - -private: - void printAux(raw_ostream &Out, bool printLocations, -const char *NL, const char *Sep) const; + + void print(raw_ostream &Out, const char *NL, const char *Sep, + const LocationContext *WithLC = nullptr) const; }; class EnvironmentManager { Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h?rev=324660&r1=324659&r2=324660&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h Thu Feb 8 14:24:38 2018 @@ -435,9 +435,10 @@ public: } // Pretty-printing. - void print(raw_ostream &Out, const char *nl = "\n", - const char *sep = "") const; - void printDOT(raw_ostream &Out) const; + void print(raw_ostream &Out, const char *nl = "\n", const char *sep = "", + const LocationContext *CurrentLC = nullptr) const; + void printDOT(raw_ostream &Out, +const LocationContext *CurrentLC = nullptr) const; void printTaint(raw_ostream &Out, const char *nl = "\n", const char *sep = "") const; Modified: cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp?rev=324660&r1=324659&r2=324660&view=diff == --- cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp (original) +++ cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp Thu Feb 8 14:24:38 2018 @@ -463,28 +463,54 @@ bool LocationContext::isParentOf(const L return false; } -void LocationContext::dumpStack(raw_ostream &OS, StringRef Indent) const { +static void printLocation(raw_ostream &OS, const SourceManager &SM, + SourceLocation SLoc) { + if (SLoc.isFileID() && SM.isInMainFile(SLoc)) +OS << "line " << SM.getExpansionLineNumber(SLoc); + else +SLoc.print(OS, SM); +} + +void LocationContext::dumpStack( +raw_ostream &OS, StringRef Indent, const char *NL, const char *Sep, +std::function printMoreInfoPerContext) const { ASTContext &Ctx = getAnalysisDeclContext()->getASTContext(); PrintingPolicy PP(Ctx.getLangOpts()); PP.TerseOutput = 1; + const Sour
r324663 - [analyzer] Self-debug: Dump the core's internal state traits to the egraph.
Author: dergachev Date: Thu Feb 8 14:32:38 2018 New Revision: 324663 URL: http://llvm.org/viewvc/llvm-project?rev=324663&view=rev Log: [analyzer] Self-debug: Dump the core's internal state traits to the egraph. It is useful for debugging problems with C++ operator new() or temporaries. Differential Revision: https://reviews.llvm.org/D42560 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=324663&r1=324662&r2=324663&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Thu Feb 8 14:32:38 2018 @@ -299,8 +299,9 @@ public: const CallEvent *Call) override; /// printState - Called by ProgramStateManager to print checker-specific data. - void printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) override; + void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, + const char *Sep, + const LocationContext *LCtx = nullptr) override; ProgramStateManager& getStateManager() override { return StateMgr; } Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h?rev=324663&r1=324662&r2=324663&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h Thu Feb 8 14:32:38 2018 @@ -155,7 +155,8 @@ public: /// printState - Called by ProgramStateManager to print checker-specific data. virtual void printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) = 0; + const char *NL, const char *Sep, + const LocationContext *LCtx = nullptr) = 0; /// Called by CoreEngine when the analysis worklist is either empty or the // maximum number of analysis steps have been reached. Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=324663&r1=324662&r2=324663&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Thu Feb 8 14:32:38 2018 @@ -383,8 +383,62 @@ ExprEngine::processRegionChanges(Program LCtx, Call); } +static void printInitializedTemporariesForContext(raw_ostream &Out, + ProgramStateRef State, + const char *NL, + const char *Sep, + const LocationContext *LC) { + PrintingPolicy PP = + LC->getAnalysisDeclContext()->getASTContext().getPrintingPolicy(); + for (auto I : State->get()) { +if (I.second != LC) + continue; +Out << '(' << I.second << ',' << I.first << ") "; +I.first->printPretty(Out, nullptr, PP); +Out << NL; + } +} + +static void printCXXNewAllocatorValuesForContext(raw_ostream &Out, + ProgramStateRef State, + const char *NL, + const char *Sep, + const LocationContext *LC) { + PrintingPolicy PP = + LC->getAnalysisDeclContext()->getASTContext().getPrintingPolicy(); + + for (auto I : State->get()) { +std::pair Key = I.first; +SVal Value = I.second; +if (Key.second != LC) + continue; +Out << '(' << Key.second << ',' << Key.first << ") "; +Key.first->printPretty(Out, nullptr, PP); +Out << " : " << Value << NL; + } +} + void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State, -const char *NL, const char *Sep) { +const char *NL, const char *Sep, +const LocationContext *LCtx) { + if (LCtx) { +if (!State->get().isEmpty()) { + Out << Sep << "Initialized temporaries:" << NL; + + LCtx
r324668 - [CFG] Add extra context to C++ constructor statement elements.
Author: dergachev Date: Thu Feb 8 14:58:15 2018 New Revision: 324668 URL: http://llvm.org/viewvc/llvm-project?rev=324668&view=rev Log: [CFG] Add extra context to C++ constructor statement elements. This patch adds a new CFGStmt sub-class, CFGConstructor, which replaces the regular CFGStmt with CXXConstructExpr in it whenever the CFG has additional information to provide regarding what sort of object is being constructed. It is useful for figuring out what memory is initialized in client of the CFG such as the Static Analyzer, which do not operate by recursive AST traversal, but instead rely on the CFG to provide all the information when they need it. Otherwise, the statement that triggers the construction and defines what memory is being initialized would normally occur after the construct-expression, and the client would need to peek to the next CFG element or use statement parent map to understand the necessary facts about the construct-expression. As a proof of concept, CFGConstructors are added for new-expressions and the respective test cases are provided to demonstrate how it works. For now, the only additional data contained in the CFGConstructor element is the "trigger statement", such as new-expression, which is the parent of the constructor. It will be significantly expanded in later commits. The additional data is organized as an auxiliary structure - the "construction context", which is allocated separately from the CFGElement. Differential Revision: https://reviews.llvm.org/D42672 Added: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Modified: cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp cfe/trunk/test/Analysis/analyzer-config.c cfe/trunk/test/Analysis/analyzer-config.cpp cfe/trunk/test/Analysis/cfg.cpp Modified: cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h?rev=324668&r1=324667&r2=324668&view=diff == --- cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h (original) +++ cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h Thu Feb 8 14:58:15 2018 @@ -439,6 +439,7 @@ public: bool synthesizeBodies = false, bool addStaticInitBranches = false, bool addCXXNewAllocator = true, + bool addRichCXXConstructors = true, CodeInjector *injector = nullptr); AnalysisDeclContext *getContext(const Decl *D); Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=324668&r1=324667&r2=324668&view=diff == --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Thu Feb 8 14:58:15 2018 @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_ANALYSIS_CFG_H #define LLVM_CLANG_ANALYSIS_CFG_H -#include "clang/AST/Stmt.h" +#include "clang/AST/ExprCXX.h" #include "clang/Analysis/Support/BumpVector.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" @@ -55,11 +55,15 @@ class CFGElement { public: enum Kind { // main kind -Statement, Initializer, NewAllocator, LifetimeEnds, LoopExit, +// stmt kind +Statement, +Constructor, +STMT_BEGIN = Statement, +STMT_END = Constructor, // dtor kind AutomaticObjectDtor, DeleteDtor, @@ -117,7 +121,9 @@ public: class CFGStmt : public CFGElement { public: - CFGStmt(Stmt *S) : CFGElement(Statement, S) {} + explicit CFGStmt(Stmt *S, Kind K = Statement) : CFGElement(K, S) { +assert(isKind(*this)); + } const Stmt *getStmt() const { return static_cast(Data1.getPointer()); @@ -126,10 +132,66 @@ public: private: friend class CFGElement; + static bool isKind(const CFGElement &E) { +return E.getKind() >= STMT_BEGIN && E.getKind() <= STMT_END; + } + +protected: CFGStmt() = default; +}; + +// This is bulky data for CFGConstructor which would not fit into the +// CFGElement's room (pair of pointers). Contains the information +// necessary to express what memory is being initialized by +// the construction. +class ConstructionContext { + // The construction site - the statement that triggered the construction + // for one of its parts. For instan
r324680 - [analyzer] MallocChecker: Fix one more bug category.
Author: dergachev Date: Thu Feb 8 15:28:29 2018 New Revision: 324680 URL: http://llvm.org/viewvc/llvm-project?rev=324680&view=rev Log: [analyzer] MallocChecker: Fix one more bug category. Even though most of the inconsistencies in MallocChecker's bug categories were fixed in r302016, one more was introduced in r301913 which was later missed. Patch by Henry Wong! Differential Revision: https://reviews.llvm.org/D43074 Added: cfe/trunk/test/Analysis/malloc-fnptr-plist.c Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=324680&r1=324679&r2=324680&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Thu Feb 8 15:28:29 2018 @@ -2075,8 +2075,8 @@ void MallocChecker::ReportFunctionPointe if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_BadFree[*CheckKind]) - BT_BadFree[*CheckKind].reset( - new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error")); + BT_BadFree[*CheckKind].reset(new BugType( + CheckNames[*CheckKind], "Bad free", categories::MemoryError)); SmallString<100> Buf; llvm::raw_svector_ostream Os(Buf); Added: cfe/trunk/test/Analysis/malloc-fnptr-plist.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/malloc-fnptr-plist.c?rev=324680&view=auto == --- cfe/trunk/test/Analysis/malloc-fnptr-plist.c (added) +++ cfe/trunk/test/Analysis/malloc-fnptr-plist.c Thu Feb 8 15:28:29 2018 @@ -0,0 +1,11 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker core,unix.Malloc -analyzer-output=plist -o %t.plist -verify %s +// RUN: FileCheck --input-file=%t.plist %s + +void free(void *); +void (*fnptr)(int); +void foo() { + free((void *)fnptr); // expected-warning{{Argument to free() is a function pointer}} +} + +// Make sure the bug category is correct. +// CHECK: categoryMemory error ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r324697 - [CFG] Squash an unused variable introduced in r324668.
Author: dergachev Date: Thu Feb 8 17:43:26 2018 New Revision: 324697 URL: http://llvm.org/viewvc/llvm-project?rev=324697&view=rev Log: [CFG] Squash an unused variable introduced in r324668. Found by -Werror buildbot. Modified: cfe/trunk/lib/Analysis/CFG.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=324697&r1=324696&r2=324697&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Thu Feb 8 17:43:26 2018 @@ -1153,7 +1153,7 @@ void CFGBuilder::EnterConstructionContex return; if (!Child) return; - if (auto *Constructor = dyn_cast(Child)) { + if (isa(Child)) { assert(CurrentConstructionContext.isNull() && "Already within a construction context!"); CurrentConstructionContext = ConstructionContext(Trigger); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r324789 - [analyzer] Add support for __builtin_constant_p.
Author: dergachev Date: Fri Feb 9 16:51:47 2018 New Revision: 324789 URL: http://llvm.org/viewvc/llvm-project?rev=324789&view=rev Log: [analyzer] Add support for __builtin_constant_p. This builtin is evaluated in compile time. But in the analyzer we don't yet automagically evaluate all calls that can be evaluated in compile time. Patch by Felix Kostenzer! Differential Revision: https://reviews.llvm.org/D42745 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp cfe/trunk/test/Analysis/builtin-functions.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp?rev=324789&r1=324788&r2=324789&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp Fri Feb 9 16:51:47 2018 @@ -96,7 +96,8 @@ bool BuiltinFunctionChecker::evalCall(co return true; } - case Builtin::BI__builtin_object_size: { + case Builtin::BI__builtin_object_size: + case Builtin::BI__builtin_constant_p: { // This must be resolvable at compile time, so we defer to the constant // evaluator for a value. SVal V = UnknownVal(); Modified: cfe/trunk/test/Analysis/builtin-functions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/builtin-functions.cpp?rev=324789&r1=324788&r2=324789&view=diff == --- cfe/trunk/test/Analysis/builtin-functions.cpp (original) +++ cfe/trunk/test/Analysis/builtin-functions.cpp Fri Feb 9 16:51:47 2018 @@ -64,3 +64,20 @@ void g(int i) { // We give up the analysis on this path. } } + +void test_constant_p() { + int i = 1; + const int j = 2; + constexpr int k = 3; + clang_analyzer_eval(__builtin_constant_p(42) == 1); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(i) == 0); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(j) == 1); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(k) == 1); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(i + 42) == 0); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(j + 42) == 1); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(k + 42) == 1); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(" ") == 1); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(test_constant_p) == 0); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(k - 3) == 0); // expected-warning {{FALSE}} + clang_analyzer_eval(__builtin_constant_p(k - 3) == 1); // expected-warning {{TRUE}} +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r324790 - [analyzer] Add missing pre-post-statement callbacks for OffsetOfExpr.
Author: dergachev Date: Fri Feb 9 16:55:49 2018 New Revision: 324790 URL: http://llvm.org/viewvc/llvm-project?rev=324790&view=rev Log: [analyzer] Add missing pre-post-statement callbacks for OffsetOfExpr. This expression may or may not be evaluated in compile time, so tracking the result symbol is of potential interest. However, run-time offsetof is not yet supported by the analyzer, so for now this callback is only there to assist future implementation. Patch by Henry Wong! Differential Revision: https://reviews.llvm.org/D42300 Added: cfe/trunk/test/Analysis/offsetofexpr-callback.c Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/test/Analysis/Inputs/system-header-simulator.h Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp?rev=324790&r1=324789&r2=324790&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp Fri Feb 9 16:55:49 2018 @@ -33,6 +33,8 @@ class AnalysisOrderChecker check::PostStmt, check::PreStmt, check::PostStmt, + check::PreStmt, + check::PostStmt, check::PreCall, check::PostCall, check::NewAllocator, @@ -91,6 +93,16 @@ public: llvm::errs() << "PostStmt\n"; } + void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { +if (isCallbackEnabled(C, "PreStmtOffsetOfExpr")) + llvm::errs() << "PreStmt\n"; + } + + void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { +if (isCallbackEnabled(C, "PostStmtOffsetOfExpr")) + llvm::errs() << "PostStmt\n"; + } + void checkPreCall(const CallEvent &Call, CheckerContext &C) const { if (isCallbackEnabled(C, "PreCall")) { llvm::errs() << "PreCall"; Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=324790&r1=324789&r2=324790&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Fri Feb 9 16:55:49 2018 @@ -1543,12 +1543,19 @@ void ExprEngine::Visit(const Stmt *S, Ex Bldr.addNodes(Dst); break; -case Stmt::OffsetOfExprClass: +case Stmt::OffsetOfExprClass: { Bldr.takeNodes(Pred); - VisitOffsetOfExpr(cast(S), Pred, Dst); + ExplodedNodeSet PreVisit; + getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); + + ExplodedNodeSet PostVisit; + for (ExplodedNode *Node : PreVisit) +VisitOffsetOfExpr(cast(S), Node, PostVisit); + + getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this); Bldr.addNodes(Dst); break; - +} case Stmt::UnaryExprOrTypeTraitExprClass: Bldr.takeNodes(Pred); VisitUnaryExprOrTypeTraitExpr(cast(S), Modified: cfe/trunk/test/Analysis/Inputs/system-header-simulator.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/system-header-simulator.h?rev=324790&r1=324789&r2=324790&view=diff == --- cfe/trunk/test/Analysis/Inputs/system-header-simulator.h (original) +++ cfe/trunk/test/Analysis/Inputs/system-header-simulator.h Fri Feb 9 16:55:49 2018 @@ -110,4 +110,6 @@ void _Exit(int status) __attribute__ ((_ #ifndef NULL #define __DARWIN_NULL 0 #define NULL __DARWIN_NULL -#endif \ No newline at end of file +#endif + +#define offsetof(t, d) __builtin_offsetof(t, d) \ No newline at end of file Added: cfe/trunk/test/Analysis/offsetofexpr-callback.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/offsetofexpr-callback.c?rev=324790&view=auto == --- cfe/trunk/test/Analysis/offsetofexpr-callback.c (added) +++ cfe/trunk/test/Analysis/offsetofexpr-callback.c Fri Feb 9 16:55:49 2018 @@ -0,0 +1,13 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.AnalysisOrder -analyzer-config debug.AnalysisOrder:PreStmtOffsetOfExpr=true,debug.AnalysisOrder:PostStmtOffsetOfExpr=true %s 2>&1 | FileCheck %s +#include "Inputs/system-header-simulator.h" + +struct S { + char c; +}; + +void test() { + offsetof(struct S, c); +} + +// CHECK: PreStmt +// CHECK-NEXT: PostStmt \ No newline at end of file ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r324794 - [CFG] Add construction context for simple variable declarations.
Author: dergachev Date: Fri Feb 9 17:55:23 2018 New Revision: 324794 URL: http://llvm.org/viewvc/llvm-project?rev=324794&view=rev Log: [CFG] Add construction context for simple variable declarations. Constructors of simple variables now can be queried to discover that they're constructing into simple variables. Differential Revision: https://reviews.llvm.org/D42699 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp cfe/trunk/test/Analysis/blocks.mm cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/cfg.cpp cfe/trunk/test/Analysis/initializers-cfg-output.cpp cfe/trunk/test/Analysis/lifetime-cfg-output.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=324794&r1=324793&r2=324794&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 9 17:55:23 2018 @@ -2377,7 +2377,9 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(D autoCreateBlock(); appendStmt(Block, DS); - + + EnterConstructionContextIfNecessary(DS, Init); + // Keep track of the last non-null block, as 'Block' can be nulled out // if the initializer expression is something like a 'while' in a // statement-expression. Modified: cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp?rev=324794&r1=324793&r2=324794&view=diff == --- cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp (original) +++ cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp Fri Feb 9 17:55:23 2018 @@ -1,5 +1,16 @@ -// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -analyzer-checker=debug.DumpCFG %s > %t 2>&1 -// RUN: FileCheck --input-file=%t %s +// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -analyzer-checker=debug.DumpCFG -analyzer-config cfg-rich-constructors=false %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,WARNINGS %s +// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -analyzer-checker=debug.DumpCFG -analyzer-config cfg-rich-constructors=true %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,ANALYZER %s + +// This file tests how we construct two different flavors of the Clang CFG - +// the CFG used by the Sema analysis-based warnings and the CFG used by the +// static analyzer. The difference in the behavior is checked via FileCheck +// prefixes (WARNINGS and ANALYZER respectively). When introducing new analyzer +// flags, no new run lines should be added - just these flags would go to the +// respective line depending on where is it turned on and where is it turned +// off. Feel free to add tests that test only one of the CFG flavors if you're +// not sure how the other flavor is supposed to work in your case. class A { public: @@ -32,7 +43,8 @@ extern const bool UV; // CHECK: [B2 (ENTRY)] // CHECK-NEXT: Succs (1): B1 // CHECK: [B1] -// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// WARNINGS-NEXT: 1: (CXXConstructExpr, class A) +// ANALYZER-NEXT: 1: (CXXConstructExpr, [B1.2], class A) // CHECK-NEXT: 2: A a; // CHECK-NEXT: 3: a // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class A) @@ -57,9 +69,11 @@ void test_const_ref() { // CHECK: [B2 (ENTRY)] // CHECK-NEXT: Succs (1): B1 // CHECK: [B1] -// CHECK-NEXT: 1: (CXXConstructExpr, class A [2]) +// WARNINGS-NEXT: 1: (CXXConstructExpr, class A [2]) +// ANALYZER-NEXT: 1: (CXXConstructExpr, [B1.2], class A [2]) // CHECK-NEXT: 2: A a[2]; -// CHECK-NEXT: 3: (CXXConstructExpr, class A [0]) +// WARNINGS-NEXT: 3: (CXXConstructExpr, class A [0]) +// ANALYZER-NEXT: 3: (CXXConstructExpr, [B1.4], class A [0]) // CHECK-NEXT: 4: A b[0]; // CHECK-NEXT: 5: [B1.2].~A() (Implicit destructor) // CHECK-NEXT: Preds (1): B2 @@ -74,15 +88,19 @@ void test_array() { // CHECK: [B2 (ENTRY)] // CHECK-NEXT: Succs (1): B1 // CHECK: [B1] -// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// WARNINGS-NEXT: 1: (CXXConstructExpr, class A) +// ANALYZER-NEXT: 1: (CXXConstructExpr, [B1.2], class A) // CHECK-NEXT: 2: A a; -// CHECK-NEXT: 3: (CXXConstructExpr, class A) +// WARNINGS-NEXT: 3: (CXXConstructExpr, class A) +// ANALYZER-NEXT: 3: (CXXConstructExpr, [B1.4], class A) // CHECK-NEXT: 4: A c; -// CHECK-NEXT: 5: (CXXConstructExpr, class A) +// WARNINGS-NEXT: 5: (CXXConstructExpr, class A) +// ANALYZER-NEXT: 5: (CXXConstructExpr, [B1.6], class A) // CHECK-NEXT: 6: A d; // CHECK-NEXT: 7: [B1.6].~A() (Implicit destructor) // CHECK-NEXT: 8: [B1.4].~A() (Implicit destructor) -// CHECK-NEXT: 9: (CXXConstructExpr, class A) +// WARNINGS-NEXT: 9: (CXXConstructExpr, class A) +/
r324796 - [CFG] Add construction context for constructor initializers.
Author: dergachev Date: Fri Feb 9 18:18:04 2018 New Revision: 324796 URL: http://llvm.org/viewvc/llvm-project?rev=324796&view=rev Log: [CFG] Add construction context for constructor initializers. CFG elements for constructors of fields and base classes that are being initialized before the body of the whole-class constructor starts can now be queried to discover that they're indeed participating in initialization of their respective fields or bases before the whole-class constructor kicks in. CFG construction contexts are now capable of representing CXXCtorInitializer triggers, which aren't considered to be statements in the Clang AST. Differential Revision: https://reviews.llvm.org/D42700 Modified: cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/initializers-cfg-output.cpp Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=324796&r1=324795&r2=324796&view=diff == --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Fri Feb 9 18:18:04 2018 @@ -145,19 +145,30 @@ protected: // necessary to express what memory is being initialized by // the construction. class ConstructionContext { +public: + typedef llvm::PointerUnion TriggerTy; + +private: // The construction site - the statement that triggered the construction // for one of its parts. For instance, stack variable declaration statement // triggers construction of itself or its elements if it's an array, // new-expression triggers construction of the newly allocated object(s). - Stmt *Trigger = nullptr; + TriggerTy Trigger; public: ConstructionContext() = default; - ConstructionContext(Stmt *Trigger) : Trigger(Trigger) {} + ConstructionContext(TriggerTy Trigger) + : Trigger(Trigger) {} - bool isNull() const { return Trigger == nullptr; } + bool isNull() const { return Trigger.isNull(); } - const Stmt *getTriggerStmt() const { return Trigger; } + const Stmt *getTriggerStmt() const { +return Trigger.dyn_cast(); + } + + const CXXCtorInitializer *getTriggerInit() const { +return Trigger.dyn_cast(); + } const ConstructionContext *getPersistentCopy(BumpVectorContext &C) const { ConstructionContext *CC = C.getAllocator().Allocate(); @@ -185,6 +196,10 @@ public: return getConstructionContext()->getTriggerStmt(); } + const CXXCtorInitializer *getTriggerInit() const { +return getConstructionContext()->getTriggerInit(); + } + private: friend class CFGElement; Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=324796&r1=324795&r2=324796&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 9 18:18:04 2018 @@ -654,7 +654,8 @@ private: // to the trigger statement. The construction context will be unset once // it is consumed when the CFG building procedure processes the // construct-expression and adds the respective CFGConstructor element. - void EnterConstructionContextIfNecessary(Stmt *Trigger, Stmt *Child); + void EnterConstructionContextIfNecessary( + ConstructionContext::TriggerTy Trigger, Stmt *Child); // Unset the construction context after consuming it. This is done immediately // after adding the CFGConstructor element, so there's no need to // do this manually in every Visit... function. @@ -1147,8 +1148,8 @@ static const VariableArrayType *FindVA(c return nullptr; } -void CFGBuilder::EnterConstructionContextIfNecessary(Stmt *Trigger, - Stmt *Child) { +void CFGBuilder::EnterConstructionContextIfNecessary( +ConstructionContext::TriggerTy Trigger, Stmt *Child) { if (!BuildOpts.AddRichCXXConstructors) return; if (!Child) @@ -1294,6 +1295,8 @@ CFGBlock *CFGBuilder::addInitializer(CXX appendInitializer(Block, I); if (Init) { +EnterConstructionContextIfNecessary(I, Init); + if (HasTemporaries) { // For expression with temporaries go directly to subexpression to omit // generating destructors for the second time. @@ -4605,6 +4608,27 @@ public: } // namespace +static void print_initializer(raw_ostream &OS, StmtPrinterHelper &Helper, + const CXXCtorInitializer *I) { + if (I->isBaseInitializer()) +OS << I->getBaseClass()->getAsCXXRecordDecl()->getName(); + else if (I->isDelegatingInitializer()) +OS << I->getTypeSourceInfo()->getType()->getAsCXXRecordDecl()->getName(); + else +OS << I->getAnyMember()->getName(); + OS << "("; + if (Expr *IE = I->getInit()) +IE->printPretty(OS, &Helper, PrintingPolicy(Helpe
r324798 - [CFG] Provide construction contexts when constructors have cleanups.
Author: dergachev Date: Fri Feb 9 18:46:14 2018 New Revision: 324798 URL: http://llvm.org/viewvc/llvm-project?rev=324798&view=rev Log: [CFG] Provide construction contexts when constructors have cleanups. Now that we make it possible to query the CFG constructor element to find information about the construction site, possible cleanup work represented by ExprWithCleanups should not prevent us from providing this information. This allows us to have a correct construction context for variables initialized "by value" via elidable copy-constructors, such as 'i' in iterator i = vector.begin(); Differential Revision: https://reviews.llvm.org/D42719 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=324798&r1=324797&r2=324798&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 9 18:46:14 2018 @@ -1158,6 +1158,8 @@ void CFGBuilder::EnterConstructionContex assert(CurrentConstructionContext.isNull() && "Already within a construction context!"); CurrentConstructionContext = ConstructionContext(Trigger); + } else if (auto *Cleanups = dyn_cast(Child)) { +EnterConstructionContextIfNecessary(Trigger, Cleanups->getSubExpr()); } } Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=324798&r1=324797&r2=324798&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Fri Feb 9 18:46:14 2018 @@ -92,18 +92,45 @@ void simpleVariableWithOperatorNewInBrac C c{new C()}; } -// TODO: Should find construction target here. // CHECK: void simpleVariableInitializedByValue() // CHECK: 1: C::get // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) // CHECK-NEXT: 3: [B1.2]() // CHECK-NEXT: 4: [B1.3] -// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, class C) +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C) // CHECK-NEXT: 6: C c = C::get(); void simpleVariableInitializedByValue() { C c = C::get(); } +// TODO: Should find construction target for the three temporaries as well. +// CHECK: void simpleVariableWithTernaryOperator(bool coin) +// CHECK:[B1] +// CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6] +// CHECK-NEXT: 2: [B1.1] +// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C) +// CHECK-NEXT: 4: C c = coin ? C::get() : C(0); +// CHECK:[B2] +// CHECK-NEXT: 1: C::get +// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 3: [B2.2]() +// CHECK-NEXT: 4: [B2.3] +// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, class C) +// CHECK:[B3] +// CHECK-NEXT: 1: 0 +// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) +// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, class C) +// CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) +// CHECK-NEXT: 5: [B3.4] +// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, class C) +// CHECK:[B4] +// CHECK-NEXT: 1: coin +// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: [B4.2] ? ... : ... +void simpleVariableWithTernaryOperator(bool coin) { + C c = coin ? C::get() : C(0); +} + // TODO: Should find construction target here. // CHECK: void referenceVariableWithConstructor() // CHECK: 1: 0 @@ -125,6 +152,34 @@ void referenceVariableWithInitializer() const C &c = C(); } +// TODO: Should find construction targets here. +// CHECK: void referenceVariableWithTernaryOperator(bool coin) +// CHECK:[B1] +// CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6] +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class C) +// CHECK-NEXT: 3: [B1.2] +// CHECK-NEXT: 4: const C &c = coin ? C::get() : C(0); +// CHECK:[B2] +// CHECK-NEXT: 1: C::get +// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 3: [B2.2]() +// CHECK-NEXT: 4: [B2.3] +// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, class C) +// CHECK:[B3] +// CHECK-NEXT: 1: 0 +// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) +// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, class C) +// CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) +// CHECK-NEXT: 5: [B3.4] +// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, class C) +// CHECK:[B4] +// CHECK-NEXT:
r324800 - [analyzer] NFC: Use CFG construction contexts instead of homemade lookahead.
Author: dergachev Date: Fri Feb 9 18:55:08 2018 New Revision: 324800 URL: http://llvm.org/viewvc/llvm-project?rev=324800&view=rev Log: [analyzer] NFC: Use CFG construction contexts instead of homemade lookahead. The analyzer was relying on peeking the next CFG element during analysis whenever it was trying to figure out what object is being constructed by a given constructor. This information is now available in the current CFG element in all cases that were previously supported by the analyzer, so no complicated lookahead is necessary anymore. No functional change intended - the context in the CFG should for now be available if and only if it was previously discoverable via CFG lookahead. Differential Revision: https://reviews.llvm.org/D42721 Modified: cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=324800&r1=324799&r2=324800&view=diff == --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Fri Feb 9 18:55:08 2018 @@ -162,6 +162,8 @@ public: bool isNull() const { return Trigger.isNull(); } + TriggerTy getTrigger() const { return Trigger; } + const Stmt *getTriggerStmt() const { return Trigger.dyn_cast(); } @@ -192,6 +194,14 @@ public: return static_cast(Data2.getPointer()); } + QualType getType() const { +return cast(getStmt())->getType(); + } + + ConstructionContext::TriggerTy getTrigger() const { +return getConstructionContext()->getTrigger(); + } + const Stmt *getTriggerStmt() const { return getConstructionContext()->getTriggerStmt(); } Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=324800&r1=324799&r2=324800&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Fri Feb 9 18:55:08 2018 @@ -665,13 +665,6 @@ private: /// constructing into an existing region. const CXXConstructExpr *findDirectConstructorForCurrentCFGElement(); - /// For a CXXConstructExpr, walk forward in the current CFG block to find the - /// CFGElement for the DeclStmt or CXXInitCtorInitializer or CXXNewExpr which - /// is directly constructed by this constructor. Returns None if the current - /// constructor expression did not directly construct into an existing - /// region. - Optional findElementDirectlyInitializedByCurrentConstructor(); - /// For a given constructor, look forward in the current CFG block to /// determine the region into which an object will be constructed by \p CE. /// When the lookahead fails, a temporary region is returned, and the Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=324800&r1=324799&r2=324800&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Fri Feb 9 18:55:08 2018 @@ -114,12 +114,14 @@ ExprEngine::getRegionForConstructedObjec const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); - // See if we're constructing an existing region by looking at the next - // element in the CFG. - - if (auto Elem = findElementDirectlyInitializedByCurrentConstructor()) { -if (Optional StmtElem = Elem->getAs()) { - if (const CXXNewExpr *CNE = dyn_cast(StmtElem->getStmt())) { + // See if we're constructing an existing region by looking at the + // current construction context. + const NodeBuilderContext &CurrBldrCtx = getBuilderContext(); + const CFGBlock *B = CurrBldrCtx.getBlock(); + const CFGElement &E = (*B)[currStmtIdx]; + if (auto CC = E.getAs()) { +if (const Stmt *TriggerStmt = CC->getTriggerStmt()) { + if (const CXXNewExpr *CNE = dyn_cast(TriggerStmt)) { if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) { // TODO: Detect when the allocator returns a null pointer. // Constructor shall not be called in this case. @@ -135,7 +137,7 @@ ExprEngine::getRegionForConstructedObjec return MR; } } - } else if (auto *DS = dyn_cast(StmtElem->getStmt())) { + } else if (auto *DS = dyn_cast(TriggerStmt)) { if (const auto *Var = dyn_cast(DS->getSingleDecl())) { if (Var->getInit() && Var-
r324801 - [analyzer] Fix a merge error in -analyzer-config tests.
Author: dergachev Date: Fri Feb 9 19:04:59 2018 New Revision: 324801 URL: http://llvm.org/viewvc/llvm-project?rev=324801&view=rev Log: [analyzer] Fix a merge error in -analyzer-config tests. It was introduced when two -analyzer-config options were added almost simultaneously in r324793 and r324668 and the option count was not rebased correctly in the tests. Fixes the buildbots. Modified: cfe/trunk/test/Analysis/analyzer-config.c cfe/trunk/test/Analysis/analyzer-config.cpp Modified: cfe/trunk/test/Analysis/analyzer-config.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.c?rev=324801&r1=324800&r2=324801&view=diff == --- cfe/trunk/test/Analysis/analyzer-config.c (original) +++ cfe/trunk/test/Analysis/analyzer-config.c Fri Feb 9 19:04:59 2018 @@ -34,4 +34,4 @@ void foo() { // CHECK-NEXT: unroll-loops = false // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 21 +// CHECK-NEXT: num-entries = 22 Modified: cfe/trunk/test/Analysis/analyzer-config.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.cpp?rev=324801&r1=324800&r2=324801&view=diff == --- cfe/trunk/test/Analysis/analyzer-config.cpp (original) +++ cfe/trunk/test/Analysis/analyzer-config.cpp Fri Feb 9 19:04:59 2018 @@ -45,4 +45,4 @@ public: // CHECK-NEXT: unroll-loops = false // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 26 +// CHECK-NEXT: num-entries = 27 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r324802 - [analyzer] NFC: Assert that our fix for noreturn destructors keeps working.
Author: dergachev Date: Fri Feb 9 19:14:22 2018 New Revision: 324802 URL: http://llvm.org/viewvc/llvm-project?rev=324802&view=rev Log: [analyzer] NFC: Assert that our fix for noreturn destructors keeps working. Massive false positives were known to be caused by continuing the analysis after a destructor with a noreturn attribute has been executed in the program but not modeled in the analyzer due to being missing in the CFG. Now that work is being done on enabling the modeling of temporary constructors and destructors in the CFG, we need to make sure that the heuristic that suppresses these false positives keeps working when such modeling is disabled. In particular, different code paths open up when the corresponding constructor is being inlined during analysis. Differential Revision: https://reviews.llvm.org/D42779 Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=324802&r1=324801&r2=324802&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Fri Feb 9 19:14:22 2018 @@ -356,20 +356,30 @@ void ExprEngine::VisitCXXConstructExpr(c // paths when no-return temporary destructors are used for assertions. const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext(); if (!ADC->getCFGBuildOptions().AddTemporaryDtors) { - const MemRegion *Target = Call->getCXXThisVal().getAsRegion(); - if (Target && isa(Target) && - Call->getDecl()->getParent()->isAnyDestructorNoReturn()) { +const MemRegion *Target = Call->getCXXThisVal().getAsRegion(); +if (Target && isa(Target) && +Call->getDecl()->getParent()->isAnyDestructorNoReturn()) { + + // If we've inlined the constructor, then DstEvaluated would be empty. + // In this case we still want a sink, which could be implemented + // in processCallExit. But we don't have that implemented at the moment, + // so if you hit this assertion, see if you can avoid inlining + // the respective constructor when analyzer-config cfg-temporary-dtors + // is set to false. + // Otherwise there's nothing wrong with inlining such constructor. + assert(!DstEvaluated.empty() && + "We should not have inlined this constructor!"); for (ExplodedNode *N : DstEvaluated) { Bldr.generateSink(CE, N, N->getState()); } - // There is no need to run the PostCall and PostStmtchecker + // There is no need to run the PostCall and PostStmt checker // callbacks because we just generated sinks on all nodes in th // frontier. return; } - } + } ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(DstPostCall, DstEvaluated, ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r324952 - [CFG] Provide construction contexts for return value constructors.
Author: dergachev Date: Mon Feb 12 14:36:36 2018 New Revision: 324952 URL: http://llvm.org/viewvc/llvm-project?rev=324952&view=rev Log: [CFG] Provide construction contexts for return value constructors. When the current function returns a C++ object by value, CFG elements for constructors that construct the return values can now be queried to discover that they're indeed participating in construction of the respective return value at the respective return statement. Differential Revision: https://reviews.llvm.org/D42875 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=324952&r1=324951&r2=324952&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Mon Feb 12 14:36:36 2018 @@ -2575,6 +2575,8 @@ CFGBlock *CFGBuilder::VisitReturnStmt(Re addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R); + EnterConstructionContextIfNecessary(R, R->getRetValue()); + // If the one of the destructors does not return, we already have the Exit // block as a successor. if (!Block->hasNoReturnElement()) Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=324952&r1=324951&r2=324952&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Mon Feb 12 14:36:36 2018 @@ -5,6 +5,7 @@ class C { public: C(); C(C *); + C(int, int); static C get(); }; @@ -224,3 +225,94 @@ public: }; } // end namespace ctor_initializers + +namespace return_stmt { + +// CHECK: C returnVariable() +// CHECK: 1: (CXXConstructExpr, [B1.2], class C) +// CHECK-NEXT: 2: C c; +// CHECK-NEXT: 3: c +// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, class C) +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C) +// CHECK-NEXT: 6: return [B1.5]; +C returnVariable() { + C c; + return c; +} + +// CHECK: C returnEmptyBraces() +// CHECK: 1: {} (CXXConstructExpr, [B1.2], class C) +// CHECK-NEXT: 2: return [B1.1]; +C returnEmptyBraces() { + return {}; +} + +// CHECK: C returnBracesWithOperatorNew() +// CHECK: 1: CFGNewAllocator(C *) +// CHECK-NEXT: 2: (CXXConstructExpr, [B1.3], class C) +// CHECK-NEXT: 3: new C([B1.2]) +// CHECK-NEXT: 4: {[B1.3]} (CXXConstructExpr, [B1.5], class C) +// CHECK-NEXT: 5: return [B1.4]; +C returnBracesWithOperatorNew() { + return {new C()}; +} + +// CHECK: C returnBracesWithMultipleItems() +// CHECK: 1: 123 +// CHECK-NEXT: 2: 456 +// CHECK-NEXT: 3: {[B1.1], [B1.2]} (CXXConstructExpr, [B1.4], class C) +// CHECK-NEXT: 4: return [B1.3]; +C returnBracesWithMultipleItems() { + return {123, 456}; +} + +// TODO: Should find construction targets for the first constructor as well. +// CHECK: C returnTemporary() +// CHECK: 1: C() (CXXConstructExpr, class C) +// CHECK-NEXT: 2: [B1.1] +// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C) +// CHECK-NEXT: 4: return [B1.3]; +C returnTemporary() { + return C(); +} + +// TODO: Should find construction targets for the first constructor as well. +// CHECK: C returnTemporaryWithArgument() +// CHECK: 1: nullptr +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *) +// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, class C) +// CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) +// CHECK-NEXT: 5: [B1.4] +// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C) +// CHECK-NEXT: 7: return [B1.6]; +C returnTemporaryWithArgument() { + return C(nullptr); +} + +// CHECK: C returnTemporaryConstructedByFunction() +// CHECK: 1: C::get +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 3: [B1.2]() +// CHECK-NEXT: 4: [B1.3] +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C) +// CHECK-NEXT: 6: return [B1.5]; +C returnTemporaryConstructedByFunction() { + return C::get(); +} + +// TODO: Should find construction targets for the first constructor as well. +// CHECK: C returnChainOfCopies() +// CHECK: 1: C::get +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 3: [B1.2]() +// CHECK-NEXT: 4: [B1.3] +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, class C) +// CHECK-NEXT: 6: C([B1.5]) (CXXFunctionalCastExpr, ConstructorConversion, class C) +// CHECK-NEXT: 7: [B1.6] +// CHECK-NEXT: 8: [B1.7] (CXXConstructExpr, [B
r325201 - [analyzer] NFC: Remove dead checks when computing DeclStmt construction region.
Author: dergachev Date: Wed Feb 14 18:30:20 2018 New Revision: 325201 URL: http://llvm.org/viewvc/llvm-project?rev=325201&view=rev Log: [analyzer] NFC: Remove dead checks when computing DeclStmt construction region. In CFG, every DeclStmt has exactly one decl, which is always a variable. It is also pointless to check that the initializer is the constructor because that's how construction contexts work now. Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=325201&r1=325200&r2=325201&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Wed Feb 14 18:30:20 2018 @@ -138,15 +138,12 @@ ExprEngine::getRegionForConstructedObjec } } } else if (auto *DS = dyn_cast(TriggerStmt)) { -if (const auto *Var = dyn_cast(DS->getSingleDecl())) { - if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) { -SVal LValue = State->getLValue(Var, LCtx); -QualType Ty = Var->getType(); -LValue = makeZeroElementRegion( -State, LValue, Ty, CallOpts.IsArrayConstructorOrDestructor); -return LValue.getAsRegion(); - } -} +const auto *Var = cast(DS->getSingleDecl()); +SVal LValue = State->getLValue(Var, LCtx); +QualType Ty = Var->getType(); +LValue = makeZeroElementRegion(State, LValue, Ty, + CallOpts.IsArrayConstructorOrDestructor); +return LValue.getAsRegion(); } // TODO: Consider other directly initialized elements. } else if (const CXXCtorInitializer *Init = CC->getTriggerInit()) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r325202 - [analyzer] Allow inlining constructors into return values.
Author: dergachev Date: Wed Feb 14 18:32:32 2018 New Revision: 325202 URL: http://llvm.org/viewvc/llvm-project?rev=325202&view=rev Log: [analyzer] Allow inlining constructors into return values. This only affects the cfg-temporary-dtors mode - in this mode we begin inlining constructors that are constructing function return values. These constructors have a correct construction context since r324952. Because temporary destructors are not only never inlined, but also don't have the correct target region yet, this change is not entirely safe. But this will be fixed in the subsequent commits, while this stays off behind the cfg-temporary-dtors flag. Lifetime extension for return values is still not modeled correctly. Differential Revision: https://reviews.llvm.org/D42875 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=325202&r1=325201&r2=325202&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Wed Feb 14 18:32:32 2018 @@ -571,6 +571,7 @@ public: struct EvalCallOptions { bool IsConstructorWithImproperlyModeledTargetRegion = false; bool IsArrayConstructorOrDestructor = false; +bool IsConstructorIntoTemporary = false; EvalCallOptions() {} }; Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=325202&r1=325201&r2=325202&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Wed Feb 14 18:32:32 2018 @@ -113,6 +113,7 @@ ExprEngine::getRegionForConstructedObjec EvalCallOptions &CallOpts) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); + MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); // See if we're constructing an existing region by looking at the // current construction context. @@ -144,6 +145,17 @@ ExprEngine::getRegionForConstructedObjec LValue = makeZeroElementRegion(State, LValue, Ty, CallOpts.IsArrayConstructorOrDestructor); return LValue.getAsRegion(); + } else if (auto *RS = dyn_cast(TriggerStmt)) { +// TODO: We should construct into a CXXBindTemporaryExpr or a +// MaterializeTemporaryExpr around the call-expression on the previous +// stack frame. Currently we re-bind the temporary to the correct region +// later, but that's not semantically correct. This of course does not +// apply when we're in the top frame. But if we are in an inlined +// function, we should be able to take the call-site CFG element, +// and it should contain (but right now it wouldn't) some sort of +// construction context that'd give us the right temporary expression. +CallOpts.IsConstructorIntoTemporary = true; +return MRMgr.getCXXTempObjectRegion(CE, LCtx); } // TODO: Consider other directly initialized elements. } else if (const CXXCtorInitializer *Init = CC->getTriggerInit()) { @@ -176,7 +188,6 @@ ExprEngine::getRegionForConstructedObjec // If we couldn't find an existing region to construct into, assume we're // constructing a temporary. Notify the caller of our failure. CallOpts.IsConstructorWithImproperlyModeledTargetRegion = true; - MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); return MRMgr.getCXXTempObjectRegion(CE, LCtx); } Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=325202&r1=325201&r2=325202&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Wed Feb 14 18:32:32 2018 @@ -670,11 +670,19 @@ ExprEngine::mayInlineCallKind(const Call if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; -// FIXME: This is a hack. We don't handle temporary destructors -// right now, so we shouldn't inline their constructors. -if (CtorExpr->getConstructionKind() == CXXConst
r325209 - [analyzer] Decide on inlining destructors via EvalCallOptions.
Author: dergachev Date: Wed Feb 14 18:51:58 2018 New Revision: 325209 URL: http://llvm.org/viewvc/llvm-project?rev=325209&view=rev Log: [analyzer] Decide on inlining destructors via EvalCallOptions. EvalCallOptions were introduced in r324018 for allowing various parts of ExprEngine to notify the inlining mechanism, while preparing for evaluating a function call, of possible difficulties with evaluating the call that they foresee. Then mayInlineCall() would still be a single place for making the decision. Use that mechanism for destructors as well - pass the necessary flags from the CFG-element-specific destructor handlers. Part of this patch accidentally leaked into r324018, which led into a change in tests; this change is reverted now, because even though the change looked correct, the underlying behavior wasn't. Both of these commits were not intended to introduce any function changes otherwise. Differential Revision: https://reviews.llvm.org/D42991 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp cfe/trunk/test/Analysis/new.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=325209&r1=325208&r2=325209&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Wed Feb 14 18:51:58 2018 @@ -55,6 +55,20 @@ public: Inline_Minimal = 0x1 }; + /// Hints for figuring out of a call should be inlined during evalCall(). + struct EvalCallOptions { +/// This call is a constructor or a destructor for which we do not currently +/// compute the this-region correctly. +bool IsCtorOrDtorWithImproperlyModeledTargetRegion = false; +/// This call is a constructor or a destructor for a single element within +/// an array, a part of array construction or destruction. +bool IsArrayCtorOrDtor = false; +/// This call is a constructor or a destructor of a temporary value. +bool IsTemporaryCtorOrDtor = false; + +EvalCallOptions() {} + }; + private: AnalysisManager &AMgr; @@ -449,7 +463,8 @@ public: void VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest, const Stmt *S, bool IsBaseDtor, - ExplodedNode *Pred, ExplodedNodeSet &Dst); + ExplodedNode *Pred, ExplodedNodeSet &Dst, + const EvalCallOptions &Options); void VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, ExplodedNode *Pred, @@ -568,14 +583,6 @@ public: const LocationContext *LCtx, ProgramStateRef State); - struct EvalCallOptions { -bool IsConstructorWithImproperlyModeledTargetRegion = false; -bool IsArrayConstructorOrDestructor = false; -bool IsConstructorIntoTemporary = false; - -EvalCallOptions() {} - }; - /// Evaluate a call, running pre- and post-call checks and allowing checkers /// to be responsible for handling the evaluation of the call itself. void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, @@ -659,6 +666,17 @@ private: const Expr *InitWithAdjustments, const Expr *Result = nullptr); + /// Returns a region representing the first element of a (possibly + /// multi-dimensional) array, for the purposes of element construction or + /// destruction. + /// + /// On return, \p Ty will be set to the base type of the array. + /// + /// If the type is not an array type at all, the original value is returned. + /// Otherwise the "IsArray" flag is set. + static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, +QualType &Ty, bool &IsArray); + /// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG /// block to find the constructor expression that directly constructed into /// the storage for this statement. Returns null if the constructor for this Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=325209&r1=325208&r2=325209&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Wed Feb 14 18:51:58 2018 @@ -802,8 +802,15 @@ void ExprEngine::ProcessAutomaticObjDtor varTy
r325210 - [CFG] Provide construction contexts for temproary objects.
Author: dergachev Date: Wed Feb 14 19:13:36 2018 New Revision: 325210 URL: http://llvm.org/viewvc/llvm-project?rev=325210&view=rev Log: [CFG] Provide construction contexts for temproary objects. Constructors of C++ temporary objects that have destructors now can be queried to discover that they're indeed constructing temporary objects. The respective CXXBindTemporaryExpr, which is also repsonsible for destroying the temporary at the end of full-expression, is now available at the construction site in the CFG. This is all the context we need to provide for temporary objects that are not lifetime extended. For lifetime-extended temporaries, more context is necessary. Differential Revision: https://reviews.llvm.org/D43056 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=325210&r1=325209&r2=325210&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Wed Feb 14 19:13:36 2018 @@ -3923,6 +3923,8 @@ CFGBlock *CFGBuilder::VisitCXXBindTempor autoCreateBlock(); appendStmt(Block, E); +EnterConstructionContextIfNecessary(E, E->getSubExpr()); + // We do not want to propagate the AlwaysAdd property. asc = asc.withAlwaysAdd(false); } @@ -3992,7 +3994,7 @@ CFGBlock *CFGBuilder::VisitCXXFunctional CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, AddStmtChoice asc) { autoCreateBlock(); - appendStmt(Block, C); + appendConstructor(Block, C); return VisitChildren(C); } Modified: cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp?rev=325210&r1=325209&r2=325210&view=diff == --- cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp (original) +++ cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp Wed Feb 14 19:13:36 2018 @@ -49,7 +49,8 @@ extern const bool UV; // CHECK-NEXT: 3: a // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class A) // CHECK-NEXT: 5: const A &b = a; -// CHECK-NEXT: 6: A() (CXXConstructExpr, class A) +// WARNINGS-NEXT: 6: A() (CXXConstructExpr, class A) +// ANALYZER-NEXT: 6: A() (CXXConstructExpr, [B1.7], class A) // CHECK-NEXT: 7: [B1.6] (BindTemporary) // CHECK-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A) // CHECK-NEXT: 9: [B1.8] Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=325210&r1=325209&r2=325210&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Wed Feb 14 19:13:36 2018 @@ -1,4 +1,4 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++11 %s > %t 2>&1 +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++11 -w %s > %t 2>&1 // RUN: FileCheck --input-file=%t %s class C { @@ -8,6 +8,7 @@ public: C(int, int); static C get(); + operator bool() const; }; typedef __typeof(sizeof(int)) size_t; @@ -226,7 +227,7 @@ public: } // end namespace ctor_initializers -namespace return_stmt { +namespace return_stmt_without_dtor { // CHECK: C returnVariable() // CHECK: 1: (CXXConstructExpr, [B1.2], class C) @@ -315,4 +316,140 @@ C returnChainOfCopies() { return C(C::get()); } -} // end namespace return_stmt +} // end namespace return_stmt_without_dtor + +namespace return_stmt_with_dtor { + +class D { +public: + D(); + ~D(); +}; + +// CHECK: return_stmt_with_dtor::D returnTemporary() +// CHECK: 1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.2], class return_stmt_with_dtor::D) +// CHECK-NEXT: 2: [B1.1] (BindTemporary) +// CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class return_stmt_with_dtor::D) +// CHECK-NEXT: 4: [B1.3] +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], class return_stmt_with_dtor::D) +// CHECK-NEXT: 6: ~return_stmt_with_dtor::D() (Temporary object destructor) +// CHECK-NEXT: 7: return [B1.5]; +D returnTemporary() { + return D(); +} + +} // end namespace return_stmt_with_dtor + +namespace temporary_object_expr_without_dtors { + +// TODO: Should provide construction context for the constructor, +// even if there is no specific trigger st
r325211 - [analyzer] Inline constructors for destroyable temporaries.
Author: dergachev Date: Wed Feb 14 19:26:43 2018 New Revision: 325211 URL: http://llvm.org/viewvc/llvm-project?rev=325211&view=rev Log: [analyzer] Inline constructors for destroyable temporaries. Since r325210, in cfg-temporary-dtors mode, we can rely on the CFG to tell us that we're indeed constructing a temporary, so we can trivially construct a temporary region and inline the constructor. Much like r325202, this is only done under the off-by-default cfg-temporary-dtors flag because the temporary destructor, even if available, will not be inlined and won't have the correct object value (target region). Unless this is fixed, it is quite unsafe to inline the constructor. If the temporary is lifetime-extended, the destructor would be an automatic destructor, which would be evaluated with a "correct" target region - modulo the series of incorrect relocations performed during the lifetime extension. It means that at least, values within the object are guaranteed to be properly escaped or invalidated. Differential Revision: https://reviews.llvm.org/D43062 Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=325211&r1=325210&r2=325211&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Wed Feb 14 19:26:43 2018 @@ -148,6 +148,9 @@ ExprEngine::getRegionForConstructedObjec // construction context that'd give us the right temporary expression. CallOpts.IsTemporaryCtorOrDtor = true; return MRMgr.getCXXTempObjectRegion(CE, LCtx); + } else if (auto *BTE = dyn_cast(TriggerStmt)) { +CallOpts.IsTemporaryCtorOrDtor = true; +return MRMgr.getCXXTempObjectRegion(CE, LCtx); } // TODO: Consider other directly initialized elements. } else if (const CXXCtorInitializer *Init = CC->getTriggerInit()) { Modified: cfe/trunk/test/Analysis/temporaries.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temporaries.cpp?rev=325211&r1=325210&r2=325211&view=diff == --- cfe/trunk/test/Analysis/temporaries.cpp (original) +++ cfe/trunk/test/Analysis/temporaries.cpp Wed Feb 14 19:26:43 2018 @@ -607,22 +607,37 @@ void test() { clang_analyzer_eval(c3.getY() == 2); // expected-warning{{TRUE}} C c4 = returnTemporaryWithConstruction(); - // Should be TRUE under TEMPORARY_DTORS once this sort of construction - // in the inlined function is supported. - clang_analyzer_eval(c4.getX() == 1); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(c4.getY() == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c4.getX() == 1); + clang_analyzer_eval(c4.getY() == 2); +#ifdef TEMPORARY_DTORS + // expected-warning@-3{{TRUE}} + // expected-warning@-3{{TRUE}} +#else + // expected-warning@-6{{UNKNOWN}} + // expected-warning@-6{{UNKNOWN}} +#endif C c5 = returnTemporaryWithAnotherFunctionWithConstruction(); - // Should be TRUE under TEMPORARY_DTORS once this sort of construction - // in the inlined function is supported. - clang_analyzer_eval(c5.getX() == 1); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(c5.getY() == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c5.getX() == 1); + clang_analyzer_eval(c5.getY() == 2); +#ifdef TEMPORARY_DTORS + // expected-warning@-3{{TRUE}} + // expected-warning@-3{{TRUE}} +#else + // expected-warning@-6{{UNKNOWN}} + // expected-warning@-6{{UNKNOWN}} +#endif C c6 = returnTemporaryWithCopyConstructionWithConstruction(); - // Should be TRUE under TEMPORARY_DTORS once this sort of construction - // in the inlined function is supported. - clang_analyzer_eval(c5.getX() == 1); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(c5.getY() == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c5.getX() == 1); + clang_analyzer_eval(c5.getY() == 2); +#ifdef TEMPORARY_DTORS + // expected-warning@-3{{TRUE}} + // expected-warning@-3{{TRUE}} +#else + // expected-warning@-6{{UNKNOWN}} + // expected-warning@-6{{UNKNOWN}} +#endif #if __cplusplus >= 201103L @@ -683,10 +698,84 @@ void test() { // expected-warning@-6{{UNKNOWN}} #endif - // Should be TRUE under TEMPORARY_DTORS once this sort of construction - // in the inlined function is supported. D d3 = returnTemporaryWithCopyConstructionWithVariableAndNonTrivialCopy(); - clang_analyzer_eval(d3.getX() == 1); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(d3.getY() == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d3.getX() == 1); + clang_analyzer_eval(d3.getY() == 2); +#ifdef TEMPORARY_DTORS + // expected-warning@-3{{TRUE}} + // expected-warning@-3{{
r325278 - [analyzer] NFC: Eliminate ParentMap lookup in mayInlineCallKind().
Author: dergachev Date: Thu Feb 15 11:01:55 2018 New Revision: 325278 URL: http://llvm.org/viewvc/llvm-project?rev=325278&view=rev Log: [analyzer] NFC: Eliminate ParentMap lookup in mayInlineCallKind(). Don't look at the parent statement to figure out if the cxx-allocator-inlining flag should kick in and prevent us from inlining the constructor within a new-expression. We now have construction contexts for that purpose. Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=325278&r1=325277&r2=325278&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Thu Feb 15 11:01:55 2018 @@ -577,6 +577,12 @@ public: ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val, const ProgramPointTag *tag = nullptr); + /// Return the CFG element corresponding to the worklist element + /// that is currently being processed by ExprEngine. + CFGElement getCurrentCFGElement() { +return (*currBldrCtx->getBlock())[currStmtIdx]; + } + /// \brief Create a new state in which the call return value is binded to the /// call origin expression. ProgramStateRef bindReturnValue(const CallEvent &Call, Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=325278&r1=325277&r2=325278&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Thu Feb 15 11:01:55 2018 @@ -109,10 +109,7 @@ ExprEngine::getRegionForConstructedObjec // See if we're constructing an existing region by looking at the // current construction context. - const NodeBuilderContext &CurrBldrCtx = getBuilderContext(); - const CFGBlock *B = CurrBldrCtx.getBlock(); - const CFGElement &E = (*B)[currStmtIdx]; - if (auto CC = E.getAs()) { + if (auto CC = getCurrentCFGElement().getAs()) { if (const Stmt *TriggerStmt = CC->getTriggerStmt()) { if (const CXXNewExpr *CNE = dyn_cast(TriggerStmt)) { if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) { Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=325278&r1=325277&r2=325278&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Thu Feb 15 11:01:55 2018 @@ -15,7 +15,6 @@ #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/ParentMap.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" @@ -639,10 +638,8 @@ ExprEngine::mayInlineCallKind(const Call const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); -// FIXME: ParentMap is slow and ugly. The callee should provide the -// necessary context. Ideally as part of the call event, or maybe as part of -// location context. -const Stmt *ParentExpr = CurLC->getParentMap().getParent(CtorExpr); +auto CC = getCurrentCFGElement().getAs(); +const Stmt *ParentExpr = CC ? CC->getTriggerStmt() : nullptr; if (ParentExpr && isa(ParentExpr) && !Opts.mayInlineCXXAllocator()) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r325282 - [analyzer] Compute the correct this-region for temporary destructors.
Author: dergachev Date: Thu Feb 15 11:17:44 2018 New Revision: 325282 URL: http://llvm.org/viewvc/llvm-project?rev=325282&view=rev Log: [analyzer] Compute the correct this-region for temporary destructors. Inline them if possible - a separate flag is added to control this. The whole thing is under the cfg-temporary-dtors flag, off by default so far. Temporary destructors are called at the end of full-expression. If the temporary is lifetime-extended, automatic destructors kick in instead, which are not addressed in this patch, and normally already work well modulo the overally broken support for lifetime extension. The patch operates by attaching the this-region to the CXXBindTemporaryExpr in the program state, and then recalling it during destruction that was triggered by that CXXBindTemporaryExpr. It has become possible because CXXBindTemporaryExpr is part of the construction context since r325210. Differential revision: https://reviews.llvm.org/D43104 Added: cfe/trunk/test/Analysis/temp-obj-dtors-option.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp cfe/trunk/test/Analysis/analyzer-config.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h?rev=325282&r1=325281&r2=325282&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h Thu Feb 15 11:17:44 2018 @@ -250,6 +250,9 @@ private: /// \sa mayInlineCXXSharedPtrDtor Optional InlineCXXSharedPtrDtor; + /// \sa mayInlineCXXTemporaryDtors + Optional InlineCXXTemporaryDtors; + /// \sa mayInlineObjCMethod Optional ObjCInliningMode; @@ -493,6 +496,17 @@ public: /// accepts the values "true" and "false". bool mayInlineCXXSharedPtrDtor(); + /// Returns true if C++ temporary destructors should be inlined during + /// analysis. + /// + /// If temporary destructors are disabled in the CFG via the + /// 'cfg-temporary-dtors' option, temporary destructors would not be + /// inlined anyway. + /// + /// This is controlled by the 'c++-temp-dtor-inlining' config option, which + /// accepts the values "true" and "false". + bool mayInlineCXXTemporaryDtors(); + /// Returns whether or not paths that go through null returns should be /// suppressed. /// Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=325282&r1=325281&r2=325282&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Thu Feb 15 11:17:44 2018 @@ -448,10 +448,6 @@ public: ExplodedNode *Pred, ExplodedNodeSet &Dst); - void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, - ExplodedNodeSet &PreVisit, - ExplodedNodeSet &Dst); - void VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, ExplodedNodeSet &Dst); @@ -696,8 +692,22 @@ private: /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts. const MemRegion *getRegionForConstructedObject(const CXXConstructExpr *CE, ExplodedNode *Pred, + const ConstructionContext *CC, EvalCallOptions &CallOpts); + /// Store the region of a C++ temporary object corresponding to a + /// CXXBindTemporaryExpr for later destruction. + static ProgramStateRef addInitializedTemporary( + ProgramStateRef State, const CXXBindTemporaryExpr *BTE, + const LocationContext *LC, const CXXTempObjectRegion *R); + + /// Check if all initialized temporary regions are clear for the given + /// context range (including FromLC, not including ToLC). + /// This is useful for assertions. + static bool areInitializedTemporariesClear(ProgramStateRef State, + const LocationContext *FromLC, + const LocationContext *ToLC)
r325284 - [analyzer] Implement path notes for temporary destructors.
Author: dergachev Date: Thu Feb 15 11:28:21 2018 New Revision: 325284 URL: http://llvm.org/viewvc/llvm-project?rev=325284&view=rev Log: [analyzer] Implement path notes for temporary destructors. Temporary destructors fire at the end of the full-expression. It is reasonable to attach the path note for entering/leaving the temporary destructor to its CXXBindTemporaryExpr. This would not affect lifetime-extended temporaries with their automatic destructors which aren't temporary destructors. The path note may be confusing in the case of destructors after elidable copy constructors. Differential Revision: https://reviews.llvm.org/D43144 Added: cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp?rev=325284&r1=325283&r2=325284&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Thu Feb 15 11:28:21 2018 @@ -579,8 +579,14 @@ getLocationForCaller(const StackFrameCon const CFGNewAllocator &Alloc = Source.castAs(); return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx); } - case CFGElement::TemporaryDtor: -llvm_unreachable("not yet implemented!"); + case CFGElement::TemporaryDtor: { +// Temporary destructors are for temporaries. They die immediately at around +// the location of CXXBindTemporaryExpr. If they are lifetime-extended, +// they'd be dealt with via an AutomaticObjectDtor instead. +const auto &Dtor = Source.castAs(); +return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM, + CallerCtx); + } case CFGElement::LifetimeEnds: case CFGElement::LoopExit: llvm_unreachable("CFGElement kind should not be on callsite!"); Added: cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp?rev=325284&view=auto == --- cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp (added) +++ cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp Thu Feb 15 11:28:21 2018 @@ -0,0 +1,64 @@ +// RUN: %clang_analyze_cc1 -analyze -analyzer-checker core -analyzer-config cfg-temporary-dtors=true -analyzer-output=text -verify %s + +namespace test_simple_temporary { +class C { + int x; + +public: + C(int x): x(x) {} // expected-note{{The value 0 is assigned to field 'x'}} + ~C() { x = 1 / x; } // expected-warning{{Division by zero}} + // expected-note@-1{{Division by zero}} +}; + +void test() { + C(0); // expected-note {{Passing the value 0 via 1st parameter 'x'}} +// expected-note@-1{{Calling constructor for 'C'}} +// expected-note@-2{{Returning from constructor for 'C'}} +// expected-note@-3{{Calling '~C'}} +} +} // end namespace test_simple_temporary + +namespace test_lifetime_extended_temporary { +class C { + int x; + +public: + C(int x): x(x) {} // expected-note{{The value 0 is assigned to field 'x'}} + void nop() const {} + ~C() { x = 1 / x; } // expected-warning{{Division by zero}} + // expected-note@-1{{Division by zero}} +}; + +void test(int coin) { + // We'd divide by zero in the temporary destructor that goes after the + // elidable copy-constructor from C(0) to the lifetime-extended temporary. + // So in fact this example has nothing to do with lifetime extension. + // Actually, it would probably be better to elide the constructor, and + // put the note for the destructor call at the closing brace after nop. + const C &c = coin ? C(1) : C(0); // expected-note {{Assuming 'coin' is 0}} + // expected-note@-1{{'?' condition is false}} + // expected-note@-2{{Passing the value 0 via 1st parameter 'x'}} + // expected-note@-3{{Calling constructor for 'C'}} + // expected-note@-4{{Returning from constructor for 'C'}} + // expected-note@-5{{Calling '~C'}} + c.nop(); +} +} // end namespace test_lifetime_extended_temporary + +namespace test_bug_after_dtor { +int glob; + +class C { +public: + C() { glob += 1; } + ~C() { glob -= 2; } // expected-note{{The value 0 is assigned to 'glob'}} +}; + +void test() { + glob = 1; + C(); // expected-note {{Calling '~C'}} + // expected-note@-1{{Returning from '~C'}} + glob = 1 / glob; // expected-warning{{Division by zero}} + // expected-note@-1{{Division by zero}} +} +} // end namespace test_bug_after_dtor
r325286 - [analyzer] Suppress temporary destructors for temporary arrays.
Author: dergachev Date: Thu Feb 15 11:34:19 2018 New Revision: 325286 URL: http://llvm.org/viewvc/llvm-project?rev=325286&view=rev Log: [analyzer] Suppress temporary destructors for temporary arrays. Array destructors, like constructors, need to be called for each element of the array separately. We do not have any mechanisms to do this in the analyzer, so for now all we do is evaluate a single constructor or destructor conservatively and give up. It automatically causes the necessary invalidation and pointer escape for the whole array, because this is how RegionStore works. Implement this conservative behavior for temporary destructors. This fixes the crash on the provided test. Differential Revision: https://reviews.llvm.org/D43149 Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=325286&r1=325285&r2=325286&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Thu Feb 15 11:34:19 2018 @@ -957,7 +957,7 @@ void ExprEngine::ProcessTemporaryDtor(co } StmtBldr.generateNode(D.getBindTemporaryExpr(), Pred, State); - QualType varType = D.getBindTemporaryExpr()->getSubExpr()->getType(); + QualType T = D.getBindTemporaryExpr()->getSubExpr()->getType(); // FIXME: Currently CleanDtorState can be empty here due to temporaries being // bound to default parameters. assert(CleanDtorState.size() <= 1); @@ -966,9 +966,22 @@ void ExprEngine::ProcessTemporaryDtor(co EvalCallOptions CallOpts; CallOpts.IsTemporaryCtorOrDtor = true; - if (!MR) + if (!MR) { CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; - VisitCXXDestructor(varType, MR, D.getBindTemporaryExpr(), + +// If we have no MR, we still need to unwrap the array to avoid destroying +// the whole array at once. Regardless, we'd eventually need to model array +// destructors properly, element-by-element. +while (const ArrayType *AT = getContext().getAsArrayType(T)) { + T = AT->getElementType(); + CallOpts.IsArrayCtorOrDtor = true; +} + } else { +// We'd eventually need to makeZeroElementRegion() trick here, +// but for now we don't have the respective construction contexts, +// so MR would always be null in this case. Do nothing for now. + } + VisitCXXDestructor(T, MR, D.getBindTemporaryExpr(), /*IsBase=*/false, CleanPred, Dst, CallOpts); } Modified: cfe/trunk/test/Analysis/temporaries.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temporaries.cpp?rev=325286&r1=325285&r2=325286&view=diff == --- cfe/trunk/test/Analysis/temporaries.cpp (original) +++ cfe/trunk/test/Analysis/temporaries.cpp Thu Feb 15 11:34:19 2018 @@ -6,6 +6,8 @@ extern bool clang_analyzer_eval(bool); extern bool clang_analyzer_warnIfReached(); void clang_analyzer_checkInlined(bool); +#include "Inputs/system-header-simulator-cxx.h"; + struct Trivial { Trivial(int x) : value(x) {} int value; @@ -892,3 +894,17 @@ void test_ternary_temporary_with_copy(in } } } // namespace test_match_constructors_and_destructors + +#if __cplusplus >= 201103L +namespace temporary_list_crash { +class C { +public: + C() {} + ~C() {} +}; + +void test() { + std::initializer_list{C(), C()}; // no-crash +} +} // namespace temporary_list_crash +#endif // C++11 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r325966 - [CFG] [analyzer] NFC: Allow more complicated construction contexts.
Author: dergachev Date: Fri Feb 23 14:20:39 2018 New Revision: 325966 URL: http://llvm.org/viewvc/llvm-project?rev=325966&view=rev Log: [CFG] [analyzer] NFC: Allow more complicated construction contexts. ConstructionContexts introduced in D42672 are an additional piece of information included with CFGConstructor elements that help the client of the CFG (such as the Static Analyzer) understand where the newly constructed object is stored. The patch refactors the ConstructionContext class to prepare for including multi-layered contexts that are being constructed gradually, layer-by-layer, as the AST is traversed. Differential Revision: https://reviews.llvm.org/D43428 Modified: cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/lib/Analysis/CFG.cpp Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=325966&r1=325965&r2=325966&view=diff == --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Fri Feb 23 14:20:39 2018 @@ -155,14 +155,35 @@ private: // new-expression triggers construction of the newly allocated object(s). TriggerTy Trigger; -public: + // Sometimes a single trigger is not enough to describe the construction site. + // In this case we'd have a chain of "partial" construction contexts. + // Some examples: + // - A constructor within in an aggregate initializer list within a variable + // would have a construction context of the initializer list with the parent + // construction context of a variable. + // - A constructor for a temporary that needs to be both destroyed + // and materialized into an elidable copy constructor would have a + // construction context of a CXXBindTemporaryExpr with the parent + // construction context of a MaterializeTemproraryExpr. + // Not all of these are currently supported. + const ConstructionContext *Parent = nullptr; + ConstructionContext() = default; - ConstructionContext(TriggerTy Trigger) - : Trigger(Trigger) {} + ConstructionContext(TriggerTy Trigger, const ConstructionContext *Parent) + : Trigger(Trigger), Parent(Parent) {} + +public: + static const ConstructionContext * + create(BumpVectorContext &C, TriggerTy Trigger, + const ConstructionContext *Parent = nullptr) { +ConstructionContext *CC = C.getAllocator().Allocate(); +return new (CC) ConstructionContext(Trigger, Parent); + } bool isNull() const { return Trigger.isNull(); } TriggerTy getTrigger() const { return Trigger; } + const ConstructionContext *getParent() const { return Parent; } const Stmt *getTriggerStmt() const { return Trigger.dyn_cast(); @@ -172,10 +193,27 @@ public: return Trigger.dyn_cast(); } - const ConstructionContext *getPersistentCopy(BumpVectorContext &C) const { -ConstructionContext *CC = C.getAllocator().Allocate(); -*CC = *this; -return CC; + bool isSameAsPartialContext(const ConstructionContext *Other) const { +assert(Other); +return (Trigger == Other->Trigger); + } + + // See if Other is a proper initial segment of this construction context + // in terms of the parent chain - i.e. a few first parents coincide and + // then the other context terminates but our context goes further - i.e., + // we are providing the same context that the other context provides, + // and a bit more above that. + bool isStrictlyMoreSpecificThan(const ConstructionContext *Other) const { +const ConstructionContext *Self = this; +while (true) { + if (!Other) +return Self; + if (!Self || !Self->isSameAsPartialContext(Other)) +return false; + Self = Self->getParent(); + Other = Other->getParent(); +} +llvm_unreachable("The above loop can only be terminated via return!"); } }; @@ -834,9 +872,9 @@ public: Elements.push_back(CFGStmt(statement), C); } - void appendConstructor(CXXConstructExpr *CE, const ConstructionContext &CC, + void appendConstructor(CXXConstructExpr *CE, const ConstructionContext *CC, BumpVectorContext &C) { -Elements.push_back(CFGConstructor(CE, CC.getPersistentCopy(C)), C); +Elements.push_back(CFGConstructor(CE, CC), C); } void appendInitializer(CXXCtorInitializer *initializer, Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=325966&r1=325965&r2=325966&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 23 14:20:39 2018 @@ -475,7 +475,8 @@ class CFGBuilder { // Information about the currently visited C++ object construction site. // This is set in the construction trigger and read when the constructor // itself is being visited. - ConstructionC
r325969 - [CFG] NFC: Speculative attempt to fix MSVC internal compiler error on buildbot.
Author: dergachev Date: Fri Feb 23 14:49:25 2018 New Revision: 325969 URL: http://llvm.org/viewvc/llvm-project?rev=325969&view=rev Log: [CFG] NFC: Speculative attempt to fix MSVC internal compiler error on buildbot. Don't use fancy initialization and member access in a DenseMap. Modified: cfe/trunk/lib/Analysis/CFG.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=325969&r1=325968&r2=325969&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 23 14:49:25 2018 @@ -476,7 +476,7 @@ class CFGBuilder { // This is set in the construction trigger and read when the constructor // itself is being visited. llvm::DenseMap - ConstructionContextMap{}; + ConstructionContextMap; bool badCFG = false; const CFG::BuildOptions &BuildOpts; @@ -497,7 +497,8 @@ public: explicit CFGBuilder(ASTContext *astContext, const CFG::BuildOptions &buildOpts) : Context(astContext), cfg(new CFG()), // crew a new CFG -BuildOpts(buildOpts) {} +ConstructionContextMap(), BuildOpts(buildOpts) {} + // buildCFG - Used by external clients to construct the CFG. std::unique_ptr buildCFG(const Decl *D, Stmt *Statement); @@ -1162,7 +1163,9 @@ void CFGBuilder::findConstructionContext assert(PreviousContext->isStrictlyMoreSpecificThan(ContextSoFar) && "Already within a different construction context!"); } else { - ConstructionContextMap[CE] = ContextSoFar; + auto Pair = + ConstructionContextMap.insert(std::make_pair(CE, ContextSoFar)); + assert(Pair.second && "Already within a construction context!"); } } else if (auto *Cleanups = dyn_cast(Child)) { findConstructionContexts(ContextSoFar, Cleanups->getSubExpr()); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r325978 - [CFG] Try to narrow down MSVC compiler crash via binary search.
Author: dergachev Date: Fri Feb 23 15:38:41 2018 New Revision: 325978 URL: http://llvm.org/viewvc/llvm-project?rev=325978&view=rev Log: [CFG] Try to narrow down MSVC compiler crash via binary search. Split the presumably offending function in two to see which part of it causes the crash to occur. The crash was introduced in r325966. r325969 did not help. Modified: cfe/trunk/lib/Analysis/CFG.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=325978&r1=325977&r2=325978&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 23 15:38:41 2018 @@ -650,6 +650,10 @@ private: return Block; } + // Remember to apply \p CC when constructing the CFG element for \p CE. + void consumeConstructionContext(const ConstructionContext *CC, + CXXConstructExpr *CE); + // Scan the child statement \p Child to find the constructor that might // have been directly triggered by the current node, \p Trigger. If such // constructor has been found, set current construction context to point @@ -1149,6 +1153,18 @@ static const VariableArrayType *FindVA(c return nullptr; } +void CFGBuilder::consumeConstructionContext(const ConstructionContext *CC, CXXConstructExpr *CE) { + if (const ConstructionContext *PreviousContext = + ConstructionContextMap.lookup(CE)) { +// We might have visited this child when we were finding construction +// contexts within its parents. +assert(PreviousContext->isStrictlyMoreSpecificThan(CC) && + "Already within a different construction context!"); + } else { +ConstructionContextMap[CE] = CC; + } +} + void CFGBuilder::findConstructionContexts( const ConstructionContext *ContextSoFar, Stmt *Child) { if (!BuildOpts.AddRichCXXConstructors) @@ -1156,17 +1172,7 @@ void CFGBuilder::findConstructionContext if (!Child) return; if (auto *CE = dyn_cast(Child)) { -if (const ConstructionContext *PreviousContext = -ConstructionContextMap.lookup(CE)) { - // We might have visited this child when we were finding construction - // contexts within its parents. - assert(PreviousContext->isStrictlyMoreSpecificThan(ContextSoFar) && - "Already within a different construction context!"); -} else { - auto Pair = - ConstructionContextMap.insert(std::make_pair(CE, ContextSoFar)); - assert(Pair.second && "Already within a construction context!"); -} +consumeConstructionContext(ContextSoFar, CE); } else if (auto *Cleanups = dyn_cast(Child)) { findConstructionContexts(ContextSoFar, Cleanups->getSubExpr()); } else if (auto *BTE = dyn_cast(Child)) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r326014 - [CFG] Provide construction contexts for lifetime-extended temporaries.
Author: dergachev Date: Fri Feb 23 18:00:30 2018 New Revision: 326014 URL: http://llvm.org/viewvc/llvm-project?rev=326014&view=rev Log: [CFG] Provide construction contexts for lifetime-extended temporaries. When constructing a temporary that is going to be lifetime-extended through a MaterializeTemporaryExpr later, CFG elements for the respective constructor can now be queried to obtain the reference to that MaterializeTemporaryExpr and therefore gain information about lifetime extension. This may produce multi-layered construction contexts when information about both temporary destruction and lifetime extension is available. Differential Revision: https://reviews.llvm.org/D43477 Modified: cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=326014&r1=326013&r2=326014&view=diff == --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Fri Feb 23 18:00:30 2018 @@ -193,6 +193,17 @@ public: return Trigger.dyn_cast(); } + const MaterializeTemporaryExpr *getMaterializedTemporary() const { +// TODO: Be more careful to ensure that there's only one MTE around. +for (const ConstructionContext *CC = this; CC; CC = CC->getParent()) { + if (const auto *MTE = dyn_cast_or_null( + CC->getTriggerStmt())) { +return MTE; + } +} +return nullptr; + } + bool isSameAsPartialContext(const ConstructionContext *Other) const { assert(Other); return (Trigger == Other->Trigger); @@ -248,6 +259,10 @@ public: return getConstructionContext()->getTriggerInit(); } + const MaterializeTemporaryExpr *getMaterializedTemporary() const { +return getConstructionContext()->getMaterializedTemporary(); + } + private: friend class CFGElement; Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=326014&r1=326013&r2=326014&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 23 18:00:30 2018 @@ -548,6 +548,8 @@ private: Stmt *Term, CFGBlock *TrueBlock, CFGBlock *FalseBlock); + CFGBlock *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE, + AddStmtChoice asc); CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc); CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); @@ -1840,6 +1842,10 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, Ad case Stmt::LambdaExprClass: return VisitLambdaExpr(cast(S), asc); +case Stmt::MaterializeTemporaryExprClass: + return VisitMaterializeTemporaryExpr(cast(S), + asc); + case Stmt::MemberExprClass: return VisitMemberExpr(cast(S), asc); @@ -2975,6 +2981,16 @@ CFGBlock *CFGBuilder::VisitForStmt(ForSt return EntryConditionBlock; } +CFGBlock * +CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE, + AddStmtChoice asc) { + findConstructionContexts( + ConstructionContext::create(cfg->getBumpVectorContext(), MTE), + MTE->getTemporary()); + + return VisitStmt(MTE, asc); +} + CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { if (asc.alwaysAdd(*this, M)) { autoCreateBlock(); @@ -4706,13 +4722,20 @@ static void print_elem(raw_ostream &OS, } else if (const CXXConstructExpr *CCE = dyn_cast(S)) { OS << " (CXXConstructExpr, "; if (Optional CE = E.getAs()) { +// TODO: Refactor into ConstructionContext::print(). if (const Stmt *S = CE->getTriggerStmt()) - Helper.handledStmt((const_cast(S)), OS); + Helper.handledStmt(const_cast(S), OS); else if (const CXXCtorInitializer *I = CE->getTriggerInit()) print_initializer(OS, Helper, I); else llvm_unreachable("Unexpected trigger kind!"); OS << ", "; +if (const Stmt *S = CE->getMaterializedTemporary()) { + if (S != CE->getTriggerStmt()) { +Helper.handledStmt(const_cast(S), OS); +OS << ", "; + } +} } OS << CCE->getType().getAsString() << ")"; } else if (const CastExpr *CE = dyn_cast(S)) { Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/ll
r326015 - [CFG] Provide construction contexts for functional cast-like constructors.
Author: dergachev Date: Fri Feb 23 18:05:11 2018 New Revision: 326015 URL: http://llvm.org/viewvc/llvm-project?rev=326015&view=rev Log: [CFG] Provide construction contexts for functional cast-like constructors. When a constructor of a temporary with a single argument is treated as a functional cast expression, skip the functional cast expression and provide the correct construction context for the temporary. Differential Revision: https://reviews.llvm.org/D43480 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=326015&r1=326014&r2=326015&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 23 18:05:11 2018 @@ -1177,6 +1177,8 @@ void CFGBuilder::findConstructionContext consumeConstructionContext(ContextSoFar, CE); } else if (auto *Cleanups = dyn_cast(Child)) { findConstructionContexts(ContextSoFar, Cleanups->getSubExpr()); + } else if (auto *Cast = dyn_cast(Child)) { +findConstructionContexts(ContextSoFar, Cast->getSubExpr()); } else if (auto *BTE = dyn_cast(Child)) { findConstructionContexts( ConstructionContext::create(cfg->getBumpVectorContext(), BTE, Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=326015&r1=326014&r2=326015&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Fri Feb 23 18:05:11 2018 @@ -105,7 +105,7 @@ void simpleVariableInitializedByValue() C c = C::get(); } -// TODO: Should find construction target for the three temporaries as well. +// TODO: Should find construction target for the elidable constructors as well. // CHECK: void simpleVariableWithTernaryOperator(bool coin) // CHECK:[B1] // CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6] @@ -121,7 +121,7 @@ void simpleVariableInitializedByValue() // CHECK:[B3] // CHECK-NEXT: 1: 0 // CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) -// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, class C) +// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C) // CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CHECK-NEXT: 5: [B3.4] // CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, class C) @@ -133,6 +133,18 @@ void simpleVariableWithTernaryOperator(b C c = coin ? C::get() : C(0); } +// CHECK: void simpleVariableWithElidableCopy() +// CHECK: 1: 0 +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *) +// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C) +// CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) +// CHECK-NEXT: 5: [B1.4] +// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C) +// CHECK-NEXT: 7: C c = C(0); +void simpleVariableWithElidableCopy() { + C c = C(0); +} + // CHECK: void referenceVariableWithConstructor() // CHECK: 1: 0 // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *) @@ -153,7 +165,7 @@ void referenceVariableWithInitializer() const C &c = C(); } -// TODO: Should find construction targets here. +// TODO: Should find construction targets for the elidable constructors as well. // CHECK: void referenceVariableWithTernaryOperator(bool coin) // CHECK:[B1] // CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6] @@ -169,7 +181,7 @@ void referenceVariableWithInitializer() // CHECK:[B3] // CHECK-NEXT: 1: 0 // CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) -// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, class C) +// CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C) // CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CHECK-NEXT: 5: [B3.4] // CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, class C) @@ -275,11 +287,10 @@ C returnTemporary() { return C(); } -// TODO: Should find construction targets for the first constructor as well. // CHECK: C returnTemporaryWithArgument() // CHECK: 1: nullptr // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *) -// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, class C) +// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C) // CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CHECK-NEXT: 5: [B1.4] // CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C) @@ -299,13 +310,12 @@ C returnTemporaryConstructedByFunction() return C::get(); } -// TODO: Should find construction targets for
r326016 - [CFG] Provide construction contexts for temporaries bound to const references.
Author: dergachev Date: Fri Feb 23 18:07:50 2018 New Revision: 326016 URL: http://llvm.org/viewvc/llvm-project?rev=326016&view=rev Log: [CFG] Provide construction contexts for temporaries bound to const references. In order to bind a temporary to a const lvalue reference, a no-op cast is added to make the temporary itself const, and only then the reference is taken (materialized). Skip the no-op cast when looking for the construction context. Differential Revision: https://reviews.llvm.org/D43481 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=326016&r1=326015&r2=326016&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 23 18:07:50 2018 @@ -1179,6 +1179,9 @@ void CFGBuilder::findConstructionContext findConstructionContexts(ContextSoFar, Cleanups->getSubExpr()); } else if (auto *Cast = dyn_cast(Child)) { findConstructionContexts(ContextSoFar, Cast->getSubExpr()); + } else if (auto *ImplicitCast = dyn_cast(Child)) { +if (ImplicitCast->getCastKind() == CK_NoOp) + findConstructionContexts(ContextSoFar, ImplicitCast->getSubExpr()); } else if (auto *BTE = dyn_cast(Child)) { findConstructionContexts( ConstructionContext::create(cfg->getBumpVectorContext(), BTE, Modified: cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp?rev=326016&r1=326015&r2=326016&view=diff == --- cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp (original) +++ cfe/trunk/test/Analysis/auto-obj-dtors-cfg-output.cpp Fri Feb 23 18:07:50 2018 @@ -50,7 +50,7 @@ extern const bool UV; // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class A) // CHECK-NEXT: 5: const A &b = a; // WARNINGS-NEXT: 6: A() (CXXConstructExpr, class A) -// ANALYZER-NEXT: 6: A() (CXXConstructExpr, [B1.7], class A) +// ANALYZER-NEXT: 6: A() (CXXConstructExpr, [B1.7], [B1.9], class A) // CHECK-NEXT: 7: [B1.6] (BindTemporary) // CHECK-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A) // CHECK-NEXT: 9: [B1.8] Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=326016&r1=326015&r2=326016&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Fri Feb 23 18:07:50 2018 @@ -155,9 +155,8 @@ void referenceVariableWithConstructor() const C &c(0); } -// TODO: Should find construction target here. // CHECK: void referenceVariableWithInitializer() -// CHECK: 1: C() (CXXConstructExpr, class C) +// CHECK: 1: C() (CXXConstructExpr, [B1.3], class C) // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class C) // CHECK-NEXT: 3: [B1.2] // CHECK-NEXT: 4: const C &c = C(); @@ -335,7 +334,7 @@ public: }; // CHECK: return_stmt_with_dtor::D returnTemporary() -// CHECK: 1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.2], class return_stmt_with_dtor::D) +// CHECK: 1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.2], [B1.4], class return_stmt_with_dtor::D) // CHECK-NEXT: 2: [B1.1] (BindTemporary) // CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class return_stmt_with_dtor::D) // CHECK-NEXT: 4: [B1.3] @@ -418,7 +417,7 @@ void referenceVariableWithConstructor() } // CHECK: void referenceVariableWithInitializer() -// CHECK: 1: temporary_object_expr_with_dtors::D() (CXXConstructExpr, [B1.2], class temporary_object_expr_with_dtors::D) +// CHECK: 1: temporary_object_expr_with_dtors::D() (CXXConstructExpr, [B1.2], [B1.4], class temporary_object_expr_with_dtors::D) // CHECK-NEXT: 2: [B1.1] (BindTemporary) // CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D) // CHECK-NEXT: 4: [B1.3] @@ -446,7 +445,7 @@ void referenceVariableWithInitializer() // CHECK-NEXT: 8: [B5.7] (BindTemporary) // CHECK:[B6] // CHECK-NEXT: 1: 0 -// CHECK-NEXT: 2: [B6.1] (CXXConstructExpr, [B6.3], class temporary_object_expr_with_dtors::D) +// CHECK-NEXT: 2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6], class temporary_object_expr_with_dtors::D) // CHECK-NEXT: 3: [B6.2] (BindTemporary) // CHECK-NEXT: 4: temporary_object_expr_with_dtors::D([B6.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_ob
r326019 - [CFG] Provide construction contexts for temporaries in conditional operators.
Author: dergachev Date: Fri Feb 23 19:10:15 2018 New Revision: 326019 URL: http://llvm.org/viewvc/llvm-project?rev=326019&view=rev Log: [CFG] Provide construction contexts for temporaries in conditional operators. When a lifetime-extended temporary is on a branch of a conditional operator, materialization of such temporary occurs after the condition is resolved. This change allows us to understand, by including the MaterializeTemporaryExpr in the construction context, the target for temporary materialization in such cases. Differential Revision: https://reviews.llvm.org/D43483 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=326019&r1=326018&r2=326019&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 23 19:10:15 2018 @@ -1187,6 +1187,9 @@ void CFGBuilder::findConstructionContext ConstructionContext::create(cfg->getBumpVectorContext(), BTE, ContextSoFar), BTE->getSubExpr()); + } else if (auto *CO = dyn_cast(Child)) { +findConstructionContexts(ContextSoFar, CO->getLHS()); +findConstructionContexts(ContextSoFar, CO->getRHS()); } } Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=326019&r1=326018&r2=326019&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Fri Feb 23 19:10:15 2018 @@ -105,7 +105,6 @@ void simpleVariableInitializedByValue() C c = C::get(); } -// TODO: Should find construction target for the elidable constructors as well. // CHECK: void simpleVariableWithTernaryOperator(bool coin) // CHECK:[B1] // CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6] @@ -117,14 +116,14 @@ void simpleVariableInitializedByValue() // CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) // CHECK-NEXT: 3: [B2.2]() // CHECK-NEXT: 4: [B2.3] -// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, class C) +// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.2], class C) // CHECK:[B3] // CHECK-NEXT: 1: 0 // CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) // CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C) // CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CHECK-NEXT: 5: [B3.4] -// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, class C) +// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.2], class C) // CHECK:[B4] // CHECK-NEXT: 1: coin // CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool) @@ -164,7 +163,6 @@ void referenceVariableWithInitializer() const C &c = C(); } -// TODO: Should find construction targets for the elidable constructors as well. // CHECK: void referenceVariableWithTernaryOperator(bool coin) // CHECK:[B1] // CHECK-NEXT: 1: [B4.2] ? [B2.5] : [B3.6] @@ -176,14 +174,14 @@ void referenceVariableWithInitializer() // CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) // CHECK-NEXT: 3: [B2.2]() // CHECK-NEXT: 4: [B2.3] -// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, class C) +// CHECK-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.3], class C) // CHECK:[B3] // CHECK-NEXT: 1: 0 // CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) // CHECK-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C) // CHECK-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CHECK-NEXT: 5: [B3.4] -// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, class C) +// CHECK-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.3], class C) // CHECK:[B4] // CHECK-NEXT: 1: coin // CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool) @@ -441,7 +439,7 @@ void referenceVariableWithInitializer() // CHECK-NEXT: 4: [B5.3] (BindTemporary) // CHECK-NEXT: 5: [B5.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D) // CHECK-NEXT: 6: [B5.5] -// CHECK-NEXT: 7: [B5.6] (CXXConstructExpr, [B5.8], class temporary_object_expr_with_dtors::D) +// CHECK-NEXT: 7: [B5.6] (CXXConstructExpr, [B5.8], [B4.3], class temporary_object_expr_with_dtors::D) // CHECK-NEXT: 8: [B5.7] (BindTemporary) // CHECK:[B6] // CHECK-NEXT: 1: 0 @@ -450,7 +448,7 @@ void referenceVariableWithInitializer() // CHECK-NEXT: 4: temporary_object_expr_with_dtors::D([B6.3]) (CXXFunctionalCastExpr, ConstructorConve
r326021 - [CFG] Keep speculatively working around an MSVC compiler crash.
Author: dergachev Date: Fri Feb 23 19:54:22 2018 New Revision: 326021 URL: http://llvm.org/viewvc/llvm-project?rev=326021&view=rev Log: [CFG] Keep speculatively working around an MSVC compiler crash. Replace if() with a switch(). Because random changes in the code seem to suppress the crash. Story so far: r325966 - Crash introduced. r325969 - Speculative fix had no effect. r325978 - Tried to bisect the offending function, crash suddenly disappeared. r326016 - After another random change in the code, bug appeared again. Modified: cfe/trunk/lib/Analysis/CFG.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=326021&r1=326020&r2=326021&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb 23 19:54:22 2018 @@ -1171,25 +1171,47 @@ void CFGBuilder::findConstructionContext const ConstructionContext *ContextSoFar, Stmt *Child) { if (!BuildOpts.AddRichCXXConstructors) return; + if (!Child) return; - if (auto *CE = dyn_cast(Child)) { -consumeConstructionContext(ContextSoFar, CE); - } else if (auto *Cleanups = dyn_cast(Child)) { + + switch(Child->getStmtClass()) { + case Stmt::CXXConstructExprClass: + case Stmt::CXXTemporaryObjectExprClass: { +consumeConstructionContext(ContextSoFar, cast(Child)); +break; + } + case Stmt::ExprWithCleanupsClass: { +auto *Cleanups = cast(Child); findConstructionContexts(ContextSoFar, Cleanups->getSubExpr()); - } else if (auto *Cast = dyn_cast(Child)) { +break; + } + case Stmt::CXXFunctionalCastExprClass: { +auto *Cast = cast(Child); findConstructionContexts(ContextSoFar, Cast->getSubExpr()); - } else if (auto *ImplicitCast = dyn_cast(Child)) { -if (ImplicitCast->getCastKind() == CK_NoOp) - findConstructionContexts(ContextSoFar, ImplicitCast->getSubExpr()); - } else if (auto *BTE = dyn_cast(Child)) { +break; + } + case Stmt::ImplicitCastExprClass: { +auto *Cast = cast(Child); +findConstructionContexts(ContextSoFar, Cast->getSubExpr()); +break; + } + case Stmt::CXXBindTemporaryExprClass: { +auto *BTE = cast(Child); findConstructionContexts( ConstructionContext::create(cfg->getBumpVectorContext(), BTE, ContextSoFar), BTE->getSubExpr()); - } else if (auto *CO = dyn_cast(Child)) { +break; + } + case Stmt::ConditionalOperatorClass: { +auto *CO = cast(Child); findConstructionContexts(ContextSoFar, CO->getLHS()); findConstructionContexts(ContextSoFar, CO->getRHS()); +break; + } + default: +break; } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r326165 - [analyzer] Fix an uninitialized field.
Author: dergachev Date: Mon Feb 26 18:53:30 2018 New Revision: 326165 URL: http://llvm.org/viewvc/llvm-project?rev=326165&view=rev Log: [analyzer] Fix an uninitialized field. Found by the analyzer! Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h?rev=326165&r1=326164&r2=326165&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h Mon Feb 26 18:53:30 2018 @@ -50,6 +50,7 @@ class FunctionSummariesTy { FunctionSummary() : TotalBasicBlocks(0), InlineChecked(0), + MayInline(0), TimesInlined(0) {} }; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r304159 - [analyzer] PthreadLockChecker: model failed pthread_mutex_destroy() calls.
Author: dergachev Date: Mon May 29 09:51:39 2017 New Revision: 304159 URL: http://llvm.org/viewvc/llvm-project?rev=304159&view=rev Log: [analyzer] PthreadLockChecker: model failed pthread_mutex_destroy() calls. pthread_mutex_destroy() may fail, returning a non-zero error number, and keeping the mutex untouched. The mutex can be used on the execution branch that follows such failure, so the analyzer shouldn't warn on using a mutex that was previously destroyed, when in fact the destroy call has failed. Patch by Malhar Thakkar! Differential revision: https://reviews.llvm.org/D32449 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp cfe/trunk/test/Analysis/pthreadlock.c Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp?rev=304159&r1=304158&r2=304159&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp Mon May 29 09:51:39 2017 @@ -25,7 +25,13 @@ using namespace ento; namespace { struct LockState { - enum Kind { Destroyed, Locked, Unlocked } K; + enum Kind { +Destroyed, +Locked, +Unlocked, +UntouchedAndPossiblyDestroyed, +UnlockedAndPossiblyDestroyed + } K; private: LockState(Kind K) : K(K) {} @@ -34,6 +40,12 @@ public: static LockState getLocked() { return LockState(Locked); } static LockState getUnlocked() { return LockState(Unlocked); } static LockState getDestroyed() { return LockState(Destroyed); } + static LockState getUntouchedAndPossiblyDestroyed() { +return LockState(UntouchedAndPossiblyDestroyed); + } + static LockState getUnlockedAndPossiblyDestroyed() { +return LockState(UnlockedAndPossiblyDestroyed); + } bool operator==(const LockState &X) const { return K == X.K; @@ -42,13 +54,20 @@ public: bool isLocked() const { return K == Locked; } bool isUnlocked() const { return K == Unlocked; } bool isDestroyed() const { return K == Destroyed; } + bool isUntouchedAndPossiblyDestroyed() const { +return K == UntouchedAndPossiblyDestroyed; + } + bool isUnlockedAndPossiblyDestroyed() const { +return K == UnlockedAndPossiblyDestroyed; + } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); } }; -class PthreadLockChecker : public Checker< check::PostStmt > { +class PthreadLockChecker +: public Checker, check::DeadSymbols> { mutable std::unique_ptr BT_doublelock; mutable std::unique_ptr BT_doubleunlock; mutable std::unique_ptr BT_destroylock; @@ -61,22 +80,31 @@ class PthreadLockChecker : public Checke }; public: void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; + void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, bool isTryLock, enum LockingSemantics semantics) const; void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const; - void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const; + void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock, + enum LockingSemantics semantics) const; void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const; void reportUseDestroyedBug(CheckerContext &C, const CallExpr *CE) const; + ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state, +const MemRegion *lockR, +const SymbolRef *sym) const; }; } // end anonymous namespace -// GDM Entry for tracking lock state. +// A stack of locks for tracking lock-unlock order. REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *) +// An entry for tracking lock states. REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState) +// Return values for unresolved calls to pthread_mutex_destroy(). +REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef) + void PthreadLockChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef state = C.getState(); @@ -113,13 +141,49 @@ void PthreadLockChecker::checkPostStmt(c FName == "lck_mtx_unlock" || FName == "lck_rw_done") ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); - else if (FName == "pthread_mutex_destroy" || - FName == "lck_mtx_destroy") -DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx)); + else if (FName == "pthread_mutex_destroy") +DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx), PthreadSemantics); + else if (FName == "lck_mtx_destroy") +DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx), XNUSemantics); else if (FName ==
r304160 - [analyzer] Initial commit for the upcoming refactoring of the IteratorChecker.
Author: dergachev Date: Mon May 29 10:03:20 2017 New Revision: 304160 URL: http://llvm.org/viewvc/llvm-project?rev=304160&view=rev Log: [analyzer] Initial commit for the upcoming refactoring of the IteratorChecker. The new checker currently contains the very core infrastructure for tracking the state of iterator-type objects in the analyzer: relating iterators to their containers, tracking symbolic begin and end iterator values for containers, and solving simple equality-type constraints over iterators. A single specific check over this infrastructure is capable of finding usage of out-of-range iterators in some simple cases. Patch by Ádám Balogh! Differential revision: https://reviews.llvm.org/D32592 Added: cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp cfe/trunk/test/Analysis/iterator-range.cpp Removed: cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp cfe/trunk/test/Analysis/iterator-past-end.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt cfe/trunk/test/Analysis/Inputs/system-header-simulator-cxx.h cfe/trunk/test/Analysis/diagnostics/explicit-suppression.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td?rev=304160&r1=304159&r2=304160&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td Mon May 29 10:03:20 2017 @@ -279,15 +279,15 @@ def VirtualCallChecker : Checker<"Virtua let ParentPackage = CplusplusAlpha in { +def IteratorRangeChecker : Checker<"IteratorRange">, + HelpText<"Check for iterators used outside their valid ranges">, + DescFile<"IteratorChecker.cpp">; + def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">, HelpText<"Method calls on a moved-from object and copying a moved-from " "object will be reported">, DescFile<"MisusedMovedObjectChecker.cpp">; -def IteratorPastEndChecker : Checker<"IteratorPastEnd">, - HelpText<"Check iterators used past end">, - DescFile<"IteratorPastEndChecker.cpp">; - } // end: "alpha.cplusplus" Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt?rev=304160&r1=304159&r2=304160&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Mon May 29 10:03:20 2017 @@ -39,7 +39,7 @@ add_clang_library(clangStaticAnalyzerChe GenericTaintChecker.cpp GTestChecker.cpp IdenticalExprChecker.cpp - IteratorPastEndChecker.cpp + IteratorChecker.cpp IvarInvalidationChecker.cpp LLVMConventionsChecker.cpp LocalizationChecker.cpp Added: cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp?rev=304160&view=auto == --- cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp (added) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp Mon May 29 10:03:20 2017 @@ -0,0 +1,833 @@ +//===-- IteratorChecker.cpp ---*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// +// +// Defines a checker for using iterators outside their range (past end). Usage +// means here dereferencing, incrementing etc. +// +//===--===// +// +// In the code, iterator can be represented as a: +// * type-I: typedef-ed pointer. Operations over such iterator, such as +// comparisons or increments, are modeled straightforwardly by the +// analyzer. +// * type-II: structure with its method bodies available. Operations over such +//iterator are inlined by the analyzer, and results of modeling +//these operations are exposing implementation details of the +//iterators, which is not necessarily helping. +// * type-III: completely opaque structure. Operations over such iterator are +// modeled conservatively, producing conjured symbols everywhere. +// +// To handle all these types in a common way we introduce a structure called +// IteratorPosition which is an abstraction of the position the iterator +// represents using symbolic expressions. The checker handles all the +// operati
r304162 - [analyzer] Support partially tainted records.
Author: dergachev Date: Mon May 29 10:42:56 2017 New Revision: 304162 URL: http://llvm.org/viewvc/llvm-project?rev=304162&view=rev Log: [analyzer] Support partially tainted records. The analyzer's taint analysis can now reason about structures or arrays originating from taint sources in which only certain sections are tainted. In particular, it also benefits modeling functions like read(), which may read tainted data into a section of a structure, but RegionStore is incapable of expressing the fact that the rest of the structure remains intact, even if we try to model read() directly. Patch by Vlad Tsyrklevich! Differential revision: https://reviews.llvm.org/D28445 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h cfe/trunk/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp cfe/trunk/test/Analysis/taint-generic.c Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h?rev=304162&r1=304161&r2=304162&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h Mon May 29 10:42:56 2017 @@ -43,6 +43,9 @@ typedef std::unique_ptr(*StoreManagerCreator)( ProgramStateManager &); +typedef llvm::ImmutableMap TaintedSubRegions; +typedef llvm::ImmutableMapRef + TaintedSubRegionsRef; //===--===// // ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState. @@ -87,6 +90,7 @@ private: Store store; // Maps a location to its current value. GenericDataMap GDM; // Custom data stored by a client of this class. unsigned refCount; + TaintedSubRegions::Factory TSRFactory; /// makeWithStore - Return a ProgramState with the same values as the current /// state with the exception of using the specified Store. @@ -343,6 +347,9 @@ public: ProgramStateRef addTaint(const Stmt *S, const LocationContext *LCtx, TaintTagType Kind = TaintTagGeneric) const; + /// Create a new state in which the value is marked as tainted. + ProgramStateRef addTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const; + /// Create a new state in which the symbol is marked as tainted. ProgramStateRef addTaint(SymbolRef S, TaintTagType Kind = TaintTagGeneric) const; @@ -351,6 +358,14 @@ public: ProgramStateRef addTaint(const MemRegion *R, TaintTagType Kind = TaintTagGeneric) const; + /// Create a new state in a which a sub-region of a given symbol is tainted. + /// This might be necessary when referring to regions that can not have an + /// individual symbol, e.g. if they are represented by the default binding of + /// a LazyCompoundVal. + ProgramStateRef addPartialTaint(SymbolRef ParentSym, + const SubRegion *SubRegion, + TaintTagType Kind = TaintTagGeneric) const; + /// Check if the statement is tainted in the current state. bool isTainted(const Stmt *S, const LocationContext *LCtx, TaintTagType Kind = TaintTagGeneric) const; Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h?rev=304162&r1=304161&r2=304162&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h Mon May 29 10:42:56 2017 @@ -35,6 +35,16 @@ template<> struct ProgramStateTrait DerivedSymTaintImpl; +template<> struct ProgramStateTrait +: public ProgramStatePartialTrait { + static void *GDMIndex() { static int index; return &index; } +}; + class TaintManager { TaintManager() {} Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp?rev=304162&r1=304161&r2=304162&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp Mon May 29 10:42:56 2017 @@ -65,21 +65,8 @@ private: /// and thus, is tainted. static bool isStdin(const Expr *E, CheckerContex
r304170 - [analyzer] Fix immutable map factory lifetime for partial taint.
Author: dergachev Date: Mon May 29 13:54:02 2017 New Revision: 304170 URL: http://llvm.org/viewvc/llvm-project?rev=304170&view=rev Log: [analyzer] Fix immutable map factory lifetime for partial taint. This should fix the leaks found by asan buildbot in r304162. Also don't store a reference to the factory with every map value, which is the only difference between ImmutableMap and ImmutableMapRef. Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h?rev=304170&r1=304169&r2=304170&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h Mon May 29 13:54:02 2017 @@ -44,8 +44,6 @@ typedef std::unique_ptr(*StoreManagerCreator)( ProgramStateManager &); typedef llvm::ImmutableMap TaintedSubRegions; -typedef llvm::ImmutableMapRef - TaintedSubRegionsRef; //===--===// // ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState. @@ -90,7 +88,6 @@ private: Store store; // Maps a location to its current value. GenericDataMap GDM; // Custom data stored by a client of this class. unsigned refCount; - TaintedSubRegions::Factory TSRFactory; /// makeWithStore - Return a ProgramState with the same values as the current /// state with the exception of using the specified Store. @@ -468,6 +465,7 @@ private: std::unique_ptr ConstraintMgr; ProgramState::GenericDataMap::Factory GDMFactory; + TaintedSubRegions::Factory TSRFactory; typedef llvm::DenseMap > GDMContextsTy; GDMContextsTy GDMContexts; Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h?rev=304170&r1=304169&r2=304170&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h Mon May 29 13:54:02 2017 @@ -39,7 +39,7 @@ template<> struct ProgramStateTrait DerivedSymTaintImpl; +typedef llvm::ImmutableMap DerivedSymTaintImpl; template<> struct ProgramStateTrait : public ProgramStatePartialTrait { static void *GDMIndex() { static int index; return &index; } Modified: cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp?rev=304170&r1=304169&r2=304170&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Mon May 29 13:54:02 2017 @@ -703,13 +703,12 @@ ProgramStateRef ProgramState::addPartial if (SubRegion == SubRegion->getBaseRegion()) return addTaint(ParentSym, Kind); - TaintedSubRegionsRef TaintedSubRegions(0, TSRFactory.getTreeFactory()); - if (const TaintedSubRegionsRef *SavedTaintedRegions = -get(ParentSym)) -TaintedSubRegions = *SavedTaintedRegions; + const TaintedSubRegions *SavedRegs = get(ParentSym); + TaintedSubRegions Regs = + SavedRegs ? *SavedRegs : stateMgr->TSRFactory.getEmptyMap(); - TaintedSubRegions = TaintedSubRegions.add(SubRegion, Kind); - ProgramStateRef NewState = set(ParentSym, TaintedSubRegions); + Regs = stateMgr->TSRFactory.add(Regs, SubRegion, Kind); + ProgramStateRef NewState = set(ParentSym, Regs); assert(NewState); return NewState; } @@ -772,18 +771,16 @@ bool ProgramState::isTainted(SymbolRef S // If this is a SymbolDerived with the same parent symbol as another // tainted SymbolDerived and a region that's a sub-region of that tainted // symbol, it's also tainted. - if (const TaintedSubRegionsRef *SymRegions = -get(SD->getParentSymbol())) { + if (const TaintedSubRegions *Regs = + get(SD->getParentSymbol())) { const TypedValueRegion *R = SD->getRegion(); -for (TaintedSubRegionsRef::iterator I = SymRegions->begin(), -E = SymRegions->end(); - I != E; ++I) { +for (auto I : *Regs) { // FIXME: The logic to identify tainted regions could be more // complete. For example, this would not currently identify // overlapping fields in a union
r304710 - [analyzer] Nullability: fix notes around synthesized ObjC property accessors.
Author: dergachev Date: Mon Jun 5 07:40:03 2017 New Revision: 304710 URL: http://llvm.org/viewvc/llvm-project?rev=304710&view=rev Log: [analyzer] Nullability: fix notes around synthesized ObjC property accessors. Nullable-to-nonnull checks used to crash when the custom bug visitor was trying to add its notes to autosynthesized accessors of Objective-C properties. Now we avoid this, mostly automatically outside of checker control, by moving the diagnostic to the parent stack frame where the accessor has been called. Differential revision: https://reviews.llvm.org/D32437 Added: cfe/trunk/test/Analysis/nullability-notes.m Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h?rev=304710&r1=304709&r2=304710&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h Mon Jun 5 07:40:03 2017 @@ -550,13 +550,15 @@ public: class PathDiagnosticCallPiece : public PathDiagnosticPiece { PathDiagnosticCallPiece(const Decl *callerD, const PathDiagnosticLocation &callReturnPos) -: PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr), - NoExit(false), callReturn(callReturnPos) {} + : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr), +NoExit(false), IsCalleeAnAutosynthesizedPropertyAccessor(false), +callReturn(callReturnPos) {} PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller) -: PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr), - NoExit(true), path(oldPath) {} - + : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr), +NoExit(true), IsCalleeAnAutosynthesizedPropertyAccessor(false), +path(oldPath) {} + const Decl *Caller; const Decl *Callee; @@ -564,6 +566,10 @@ class PathDiagnosticCallPiece : public P // call exit. bool NoExit; + // Flag signifying that the callee function is an Objective-C autosynthesized + // property getter or setter. + bool IsCalleeAnAutosynthesizedPropertyAccessor; + // The custom string, which should appear after the call Return Diagnostic. // TODO: Should we allow multiple diagnostics? std::string CallStackMessage; Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp?rev=304710&r1=304709&r2=304710&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp Mon Jun 5 07:40:03 2017 @@ -326,7 +326,7 @@ NullabilityChecker::NullabilityBugVisito // Retrieve the associated statement. const Stmt *S = TrackedNullab->getNullabilitySource(); - if (!S) { + if (!S || S->getLocStart().isInvalid()) { S = PathDiagnosticLocation::getStmt(N); } Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp?rev=304710&r1=304709&r2=304710&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Mon Jun 5 07:40:03 2017 @@ -694,7 +694,30 @@ PathDiagnosticLocation::create(const Pro return PathDiagnosticLocation(S, SMng, P.getLocationContext()); } +static const LocationContext * +findTopAutosynthesizedParentContext(const LocationContext *LC) { + assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized()); + const LocationContext *ParentLC = LC->getParent(); + assert(ParentLC && "We don't start analysis from autosynthesized code"); + while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) { +LC = ParentLC; +ParentLC = LC->getParent(); +assert(ParentLC && "We don't start analysis from autosynthesized code"); + } + return LC; +} + const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { + // We cannot place diagnostics on autosynthesized code. + // Put them onto the call site through which we jumped into autosynthesized + // code for the first time. + const LocationContext *LC = N->getLocationContext(); + if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) { +// It must be a stack frame because we only autosynthesize functions. +return cast(findTopAutosynthesizedParentContex
r304713 - [analyzer] Don't add arrow to the inlined function's decl when it has no body.
Author: dergachev Date: Mon Jun 5 08:36:28 2017 New Revision: 304713 URL: http://llvm.org/viewvc/llvm-project?rev=304713&view=rev Log: [analyzer] Don't add arrow to the inlined function's decl when it has no body. In plist output mode with alternate path diagnostics, when entering a function, we draw an arrow from the caller to the beginning of the callee's declaration. Upon exiting, however, we draw the arrow from the last statement in the callee function. The former makes little sense when the declaration is not a definition, i.e. has no body, which may happen in case the body is coming from a body farm, eg. Objective-C autosynthesized property accessor. Differential Revision: https://reviews.llvm.org/D33671 Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp cfe/trunk/test/Analysis/nullability-notes.m Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp?rev=304713&r1=304712&r2=304713&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp Mon Jun 5 08:36:28 2017 @@ -1671,9 +1671,15 @@ static bool GenerateAlternateExtensivePa // Add an edge to the start of the function. const StackFrameContext *CalleeLC = CE->getCalleeContext(); const Decl *D = CalleeLC->getDecl(); -addEdgeToPath(PD.getActivePath(), PrevLoc, - PathDiagnosticLocation::createBegin(D, SM), - CalleeLC); +// Add the edge only when the callee has body. We jump to the beginning +// of the *declaration*, however we expect it to be followed by the +// body. This isn't the case for autosynthesized property accessors in +// Objective-C. No need for a similar extra check for CallExit points +// because the exit edge comes from a statement (i.e. return), +// not from declaration. +if (D->hasBody()) + addEdgeToPath(PD.getActivePath(), PrevLoc, +PathDiagnosticLocation::createBegin(D, SM), CalleeLC); // Did we visit an entire call? bool VisitedEntireCall = PD.isWithinCall(); Modified: cfe/trunk/test/Analysis/nullability-notes.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/nullability-notes.m?rev=304713&r1=304712&r2=304713&view=diff == --- cfe/trunk/test/Analysis/nullability-notes.m (original) +++ cfe/trunk/test/Analysis/nullability-notes.m Mon Jun 5 08:36:28 2017 @@ -1,11 +1,13 @@ // RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-output=text -verify %s +// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-output=plist -analyzer-config path-diagnostics-alternate=true -o %t.plist %s +// RUN: FileCheck --input-file=%t.plist %s #include "Inputs/system-header-simulator-for-nullability.h" void takesNonnull(NSObject *_Nonnull y); @interface ClassWithProperties: NSObject -@property(copy, nullable) NSObject *x; +@property(copy, nullable) NSObject *x; // plist check ensures no control flow piece from here to 'self.x'. -(void) method; @end; @implementation ClassWithProperties @@ -16,3 +18,187 @@ void takesNonnull(NSObject *_Nonnull y); // expected-note@-1{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}} } @end + +// CHECK: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:line16 +// CHECK-NEXT:col3 +// CHECK-NEXT:file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:line16 +// CHECK-NEXT:col10 +// CHECK-NEXT:file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:line16 +// CHECK-NEXT:col22 +// CHECK-NEXT:file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:line16 +// CHECK-NEXT:col22 +// CHECK-NEXT:file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEX
r305211 - [analyzer] Fix a crash when an ObjC object is constructed in AllocaRegion.
Author: dergachev Date: Mon Jun 12 12:59:50 2017 New Revision: 305211 URL: http://llvm.org/viewvc/llvm-project?rev=305211&view=rev Log: [analyzer] Fix a crash when an ObjC object is constructed in AllocaRegion. Memory region allocated by alloca() carries no implicit type information. Don't crash when resolving the init message for an Objective-C object that is being constructed in such region. rdar://problem/32517077 Differential Revision: https://reviews.llvm.org/D33828 Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp cfe/trunk/test/Analysis/DynamicTypePropagation.m Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=305211&r1=305210&r2=305211&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Mon Jun 12 12:59:50 2017 @@ -957,6 +957,12 @@ RuntimeDefinition ObjCMethodCall::getRun return RuntimeDefinition(); DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver); + if (!DTI.isValid()) { +assert(isa(Receiver) && + "Unhandled untyped region class!"); +return RuntimeDefinition(); + } + QualType DynType = DTI.getType(); CanBeSubClassed = DTI.canBeASubClass(); ReceiverT = dyn_cast(DynType.getCanonicalType()); Modified: cfe/trunk/test/Analysis/DynamicTypePropagation.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/DynamicTypePropagation.m?rev=305211&r1=305210&r2=305211&view=diff == --- cfe/trunk/test/Analysis/DynamicTypePropagation.m (original) +++ cfe/trunk/test/Analysis/DynamicTypePropagation.m Mon Jun 12 12:59:50 2017 @@ -4,6 +4,9 @@ # error Compiler does not support Objective-C generics? #endif +typedef __typeof(sizeof(int)) size_t; +void *memset(void *, int, size_t); + #define nil 0 typedef unsigned long NSUInteger; typedef int BOOL; @@ -21,6 +24,7 @@ __attribute__((objc_root_class)) @end @interface NSArray : NSObject +- (void) init; - (BOOL)contains:(ObjectType)obj; - (ObjectType)getObjAtIndex:(NSUInteger)idx; - (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx; @@ -55,3 +59,11 @@ void testArgument(NSArray *arr // MyType! [element myFunction:0 myParam:0 ]; } + +// Do not try this at home! The analyzer shouldn't crash though when it +// tries to figure out the dynamic type behind the alloca's return value. +void testAlloca(size_t NSArrayClassSizeWeKnowSomehow) { + NSArray *arr = __builtin_alloca(NSArrayClassSizeWeKnowSomehow); + memset(arr, 0, NSArrayClassSizeWeKnowSomehow); + [arr init]; // no-crash +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r305896 - [analyzer] LocalizationChecker: Support new localizable APIs.
Author: dergachev Date: Wed Jun 21 06:12:07 2017 New Revision: 305896 URL: http://llvm.org/viewvc/llvm-project?rev=305896&view=rev Log: [analyzer] LocalizationChecker: Support new localizable APIs. Add support for new methods that were added in macOS High Sierra & iOS 11 and require a localized string. Patch by Kulpreet Chilana! rdar://problem/32795210 Differential Revision: https://reviews.llvm.org/D34266 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp?rev=305896&r1=305895&r2=305896&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp Wed Jun 21 06:12:07 2017 @@ -281,6 +281,9 @@ void NonLocalizedStringChecker::initUIMe IdentifierInfo *setLabelNSSegmentedControl[] = { &Ctx.Idents.get("setLabel"), &Ctx.Idents.get("forSegment")}; ADD_METHOD(NSSegmentedControl, setLabelNSSegmentedControl, 2, 0) + IdentifierInfo *setToolTipNSSegmentedControl[] = { + &Ctx.Idents.get("setToolTip"), &Ctx.Idents.get("forSegment")}; + ADD_METHOD(NSSegmentedControl, setToolTipNSSegmentedControl, 2, 0) NEW_RECEIVER(NSButtonCell) ADD_UNARY_METHOD(NSButtonCell, setTitle, 0) @@ -562,6 +565,46 @@ void NonLocalizedStringChecker::initUIMe IdentifierInfo *setTitleUISegmentedControl[] = { &Ctx.Idents.get("setTitle"), &Ctx.Idents.get("forSegmentAtIndex")}; ADD_METHOD(UISegmentedControl, setTitleUISegmentedControl, 2, 0) + + NEW_RECEIVER(NSAccessibilityCustomRotorItemResult) + IdentifierInfo + *initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult[] = { + &Ctx.Idents.get("initWithItemLoadingToken"), + &Ctx.Idents.get("customLabel")}; + ADD_METHOD(NSAccessibilityCustomRotorItemResult, + initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult, 2, 1) + ADD_UNARY_METHOD(NSAccessibilityCustomRotorItemResult, setCustomLabel, 0) + + NEW_RECEIVER(UIContextualAction) + IdentifierInfo *contextualActionWithStyleUIContextualAction[] = { + &Ctx.Idents.get("contextualActionWithStyle"), &Ctx.Idents.get("title"), + &Ctx.Idents.get("handler")}; + ADD_METHOD(UIContextualAction, contextualActionWithStyleUIContextualAction, 3, + 1) + ADD_UNARY_METHOD(UIContextualAction, setTitle, 0) + + NEW_RECEIVER(NSAccessibilityCustomRotor) + IdentifierInfo *initWithLabelNSAccessibilityCustomRotor[] = { + &Ctx.Idents.get("initWithLabel"), &Ctx.Idents.get("itemSearchDelegate")}; + ADD_METHOD(NSAccessibilityCustomRotor, + initWithLabelNSAccessibilityCustomRotor, 2, 0) + ADD_UNARY_METHOD(NSAccessibilityCustomRotor, setLabel, 0) + + NEW_RECEIVER(NSWindowTab) + ADD_UNARY_METHOD(NSWindowTab, setTitle, 0) + ADD_UNARY_METHOD(NSWindowTab, setToolTip, 0) + + NEW_RECEIVER(NSAccessibilityCustomAction) + IdentifierInfo *initWithNameNSAccessibilityCustomAction[] = { + &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("handler")}; + ADD_METHOD(NSAccessibilityCustomAction, + initWithNameNSAccessibilityCustomAction, 2, 0) + IdentifierInfo *initWithNameTargetNSAccessibilityCustomAction[] = { + &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("target"), + &Ctx.Idents.get("selector")}; + ADD_METHOD(NSAccessibilityCustomAction, + initWithNameTargetNSAccessibilityCustomAction, 3, 0) + ADD_UNARY_METHOD(NSAccessibilityCustomAction, setName, 0) } #define LSF_INSERT(function_name) LSF.insert(&Ctx.Idents.get(function_name)); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r305900 - [analyzer] Bump a few default performance thresholds.
Author: dergachev Date: Wed Jun 21 06:29:35 2017 New Revision: 305900 URL: http://llvm.org/viewvc/llvm-project?rev=305900&view=rev Log: [analyzer] Bump a few default performance thresholds. This makes the analyzer around 10% slower by default, allowing it to find deeper bugs. Default values for the following -analyzer-config change: max-nodes: 15 -> 225000; max-inlinable-size: 50 -> 100. rdar://problem/32539666 Differential Revision: https://reviews.llvm.org/D34277 Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp cfe/trunk/test/Analysis/analyzer-config.c cfe/trunk/test/Analysis/analyzer-config.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp?rev=305900&r1=305899&r2=305900&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp Wed Jun 21 06:29:35 2017 @@ -293,7 +293,7 @@ unsigned AnalyzerOptions::getMaxInlinabl DefaultValue = 4; break; case UMK_Deep: -DefaultValue = 50; +DefaultValue = 100; break; } @@ -332,7 +332,7 @@ unsigned AnalyzerOptions::getMaxNodesPer DefaultValue = 75000; break; case UMK_Deep: -DefaultValue = 15; +DefaultValue = 225000; break; } MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue); Modified: cfe/trunk/test/Analysis/analyzer-config.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.c?rev=305900&r1=305899&r2=305900&view=diff == --- cfe/trunk/test/Analysis/analyzer-config.c (original) +++ cfe/trunk/test/Analysis/analyzer-config.c Wed Jun 21 06:29:35 2017 @@ -19,8 +19,8 @@ void foo() { // CHECK-NEXT: ipa = dynamic-bifurcate // CHECK-NEXT: ipa-always-inline-size = 3 // CHECK-NEXT: leak-diagnostics-reference-allocation = false -// CHECK-NEXT: max-inlinable-size = 50 -// CHECK-NEXT: max-nodes = 15 +// CHECK-NEXT: max-inlinable-size = 100 +// CHECK-NEXT: max-nodes = 225000 // CHECK-NEXT: max-times-inline-large = 32 // CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14 // CHECK-NEXT: mode = deep Modified: cfe/trunk/test/Analysis/analyzer-config.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.cpp?rev=305900&r1=305899&r2=305900&view=diff == --- cfe/trunk/test/Analysis/analyzer-config.cpp (original) +++ cfe/trunk/test/Analysis/analyzer-config.cpp Wed Jun 21 06:29:35 2017 @@ -30,8 +30,8 @@ public: // CHECK-NEXT: ipa = dynamic-bifurcate // CHECK-NEXT: ipa-always-inline-size = 3 // CHECK-NEXT: leak-diagnostics-reference-allocation = false -// CHECK-NEXT: max-inlinable-size = 50 -// CHECK-NEXT: max-nodes = 15 +// CHECK-NEXT: max-inlinable-size = 100 +// CHECK-NEXT: max-nodes = 225000 // CHECK-NEXT: max-times-inline-large = 32 // CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14 // CHECK-NEXT: mode = deep ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r321128 - [analyzer] Fix a crash during C++17 aggregate construction of base objects.
Author: dergachev Date: Tue Dec 19 16:40:38 2017 New Revision: 321128 URL: http://llvm.org/viewvc/llvm-project?rev=321128&view=rev Log: [analyzer] Fix a crash during C++17 aggregate construction of base objects. Since C++17, classes that have base classes can potentially be initialized as aggregates. Trying to construct such objects through brace initialization was causing the analyzer to crash when the base class has a non-trivial constructor, while figuring target region for the base class constructor, because the parent stack frame didn't contain the constructor of the subclass, because there is no constructor for subclass, merely aggregate initialization. This patch avoids the crash, but doesn't provide the actually correct region for the constructor, which still remains to be fixed. Instead, construction goes into a fake temporary region which would be immediately discarded. Similar extremely conservative approach is used for other cases in which the logic for finding the target region is not yet implemented, including aggregate initialization with fields instead of base-regions (which is not C++17-specific but also never worked, just didn't crash). Differential revision: https://reviews.llvm.org/D40841 rdar://problem/35441058 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/test/Analysis/initializer.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp?rev=321128&r1=321127&r2=321128&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp Tue Dec 19 16:40:38 2017 @@ -22,6 +22,7 @@ //===--===// #include "ClangSACheckers.h" +#include "clang/AST/ParentMap.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -262,8 +263,19 @@ void DynamicTypePropagation::checkPostCa if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { // We just finished a base constructor. Now we can use the subclass's // type when resolving virtual calls. -const Decl *D = C.getLocationContext()->getDecl(); -recordFixedType(Target, cast(D), C); +const LocationContext *LCtx = C.getLocationContext(); + +// FIXME: In C++17 classes with non-virtual bases may be treated as +// aggregates, and in such case no top-frame constructor will be called. +// Figure out if we need to do anything in this case. +// FIXME: Instead of relying on the ParentMap, we should have the +// trigger-statement (InitListExpr in this case) available in this +// callback, ideally as part of CallEvent. +if (dyn_cast_or_null( +LCtx->getParentMap().getParent(Ctor->getOriginExpr( + return; + +recordFixedType(Target, cast(LCtx->getDecl()), C); } return; } Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=321128&r1=321127&r2=321128&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Tue Dec 19 16:40:38 2017 @@ -14,6 +14,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/ParentMap.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" @@ -267,6 +268,23 @@ void ExprEngine::VisitCXXConstructExpr(c } // FALLTHROUGH case CXXConstructExpr::CK_NonVirtualBase: +// In C++17, classes with non-virtual bases may be aggregates, so they would +// be initialized as aggregates without a constructor call, so we may have +// a base class constructed directly into an initializer list without +// having the derived-class constructor call on the previous stack frame. +// Initializer lists may be nested into more initializer lists that +// correspond to surrounding aggregate initializations. +// FIXME: For now this code essentially bails out. We need to find the +// correct target region and set it. +// FIXME: Instead of relying on the ParentMap, we should have the +// trigger-statement (InitListExpr in this case) passed down from CFG or +// otherwise always available during construction. +if (dyn_cast_o
r321130 - [analyzer] trackNullOrUndefValue: track last store to non-variables.
Author: dergachev Date: Tue Dec 19 16:47:17 2017 New Revision: 321130 URL: http://llvm.org/viewvc/llvm-project?rev=321130&view=rev Log: [analyzer] trackNullOrUndefValue: track last store to non-variables. When reporting certain kinds of analyzer warnings, we use the bugreporter::trackNullOrUndefValue mechanism, which is part of public checker API, to understand where a zero, null-pointer, or garbage value came from, which would highlight important events with respect to that value in the diagnostic path notes, and help us suppress various false positives that result from values appearing from particular sources. Previously, we've lost track of the value when it was written into a memory region that is not a plain variable. Now try to resume tracking in this situation by finding where the last write to this region has occured. Differential revision: https://reviews.llvm.org/D41253 Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c cfe/trunk/test/Analysis/nullptr.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp?rev=321130&r1=321129&r2=321130&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp Tue Dec 19 16:47:17 2017 @@ -1142,9 +1142,12 @@ bool bugreporter::trackNullOrUndefValue( else RVal = state->getSVal(L->getRegion()); -const MemRegion *RegionRVal = RVal.getAsRegion(); report.addVisitor(llvm::make_unique(L->getRegion())); +if (Optional KV = RVal.getAs()) + report.addVisitor(llvm::make_unique( + *KV, L->getRegion(), EnableNullFPSuppression)); +const MemRegion *RegionRVal = RVal.getAsRegion(); if (RegionRVal && isa(RegionRVal)) { report.markInteresting(RegionRVal); report.addVisitor(llvm::make_unique( Modified: cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c?rev=321130&r1=321129&r2=321130&view=diff == --- cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c (original) +++ cfe/trunk/test/Analysis/inlining/inline-defensive-checks.c Tue Dec 19 16:47:17 2017 @@ -190,3 +190,21 @@ void idcTrackZeroValueThroughUnaryPointe idc(s); *(&(s->a[0])) = 7; // no-warning } + +void idcTrackConstraintThroughSymbolicRegion(int **x) { + idc(*x); + // FIXME: Should not warn. + **x = 7; // expected-warning{{Dereference of null pointer}} +} + +int *idcPlainNull(int coin) { + if (coin) +return 0; + static int X; + return &X; +} + +void idcTrackZeroValueThroughSymbolicRegion(int coin, int **x) { + *x = idcPlainNull(coin); + **x = 7; // no-warning +} Modified: cfe/trunk/test/Analysis/nullptr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/nullptr.cpp?rev=321130&r1=321129&r2=321130&view=diff == --- cfe/trunk/test/Analysis/nullptr.cpp (original) +++ cfe/trunk/test/Analysis/nullptr.cpp Tue Dec 19 16:47:17 2017 @@ -142,8 +142,9 @@ void shouldNotCrash() { // expected-note@-1{{Passing null pointer value via 1st parameter 'x'}} if (getSymbol()) { // expected-note {{Assuming the condition is true}} // expected-note@-1{{Taking true branch}} -X *x = Type().x; // expected-note{{'x' initialized to a null pointer value}} -x->f(); // expected-warning{{Called C++ object pointer is null}} +X *xx = Type().x; // expected-note {{Null pointer value stored to field 'x'}} + // expected-note@-1{{'xx' initialized to a null pointer value}} +xx->f(); // expected-warning{{Called C++ object pointer is null}} // expected-note@-1{{Called C++ object pointer is null}} } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r321135 - [analyzer] De-duplicate path diagnostics for each exploded graph node.
Author: dergachev Date: Tue Dec 19 17:17:53 2017 New Revision: 321135 URL: http://llvm.org/viewvc/llvm-project?rev=321135&view=rev Log: [analyzer] De-duplicate path diagnostics for each exploded graph node. The bugreporter::trackNullOrUndefValue() mechanism contains a system of bug reporter visitors that recursively call each other in order to track where a null or undefined value came from, where each visitor represents a particular tracking mechanism (track how the value was stored, track how the value was returned from a function, track how the value was constrained to null, etc.). Each visitor is only added once per value it needs to track. Almost. One exception from this rule would be FindLastStoreBRVisitor that has two operation modes: it contains a flag that indicates whether null stored values should be suppressed. Two instances of FindLastStoreBRVisitor with different values of this flag are considered to be different visitors, so they can be added twice and produce the same diagnostic twice. This was indeed the case in the affected test. With the current logic of this whole machinery, such duplication seems unavoidable. We should be able to safely add visitors with different flag values without constructing duplicate diagnostic pieces. Hence the effort in this commit to de-duplicate diagnostics regardless of what visitors have produced them. Differential Revision: https://reviews.llvm.org/D41258 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp cfe/trunk/test/Analysis/inlining/path-notes.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h?rev=321135&r1=321134&r2=321135&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h Tue Dec 19 17:17:53 2017 @@ -334,7 +334,7 @@ public: // Path "pieces" for path-sensitive diagnostics. //===--===// -class PathDiagnosticPiece { +class PathDiagnosticPiece: public llvm::FoldingSetNode { public: enum Kind { ControlFlow, Event, Macro, Call, Note }; enum DisplayHint { Above, Below }; Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp?rev=321135&r1=321134&r2=321135&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp Tue Dec 19 17:17:53 2017 @@ -885,8 +885,12 @@ static bool GenerateMinimalPathDiagnosti if (NextNode) { // Add diagnostic pieces from custom visitors. BugReport *R = PDB.getBugReport(); + llvm::FoldingSet DeduplicationSet; for (auto &V : visitors) { if (auto p = V->VisitNode(N, NextNode, PDB, *R)) { + if (DeduplicationSet.GetOrInsertNode(p.get()) != p.get()) +continue; + updateStackPiecesWithMessage(*p, CallStack); PD.getActivePath().push_front(std::move(p)); } @@ -1584,8 +1588,12 @@ static bool GenerateExtensivePathDiagnos // Add pieces from custom visitors. BugReport *R = PDB.getBugReport(); +llvm::FoldingSet DeduplicationSet; for (auto &V : visitors) { if (auto p = V->VisitNode(N, NextNode, PDB, *R)) { +if (DeduplicationSet.GetOrInsertNode(p.get()) != p.get()) + continue; + const PathDiagnosticLocation &Loc = p->getLocation(); EB.addEdge(Loc, true); updateStackPiecesWithMessage(*p, CallStack); @@ -1879,8 +1887,12 @@ static bool GenerateAlternateExtensivePa continue; // Add pieces from custom visitors. +llvm::FoldingSet DeduplicationSet; for (auto &V : visitors) { if (auto p = V->VisitNode(N, NextNode, PDB, *report)) { +if (DeduplicationSet.GetOrInsertNode(p.get()) != p.get()) + continue; + addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), PDB.LC); updateStackPiecesWithMessage(*p, CallStack); PD.getActivePath().push_front(std::move(p)); Modified: cfe/trunk/test/Analysis/inlining/path-notes.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/path-notes.cpp?rev=321135&r1=321134&r2=321135&view=diff == --- cfe/trunk/test/Analysis/inlining/path-notes.cpp (original) +++ cfe/trunk/test/Analysis/inlining/path-notes.cpp Tue Dec 19 17:17:53 2017 @@ -163,10 +163,8 @@ namespace ReturnZeroNote { const int &getZeroByRef() { static int
r321290 - [analyzer] Fix zero-initialization of stack VLAs under ObjC ARC.
Author: dergachev Date: Thu Dec 21 10:43:02 2017 New Revision: 321290 URL: http://llvm.org/viewvc/llvm-project?rev=321290&view=rev Log: [analyzer] Fix zero-initialization of stack VLAs under ObjC ARC. Using ARC, strong, weak, and autoreleasing stack variables are implicitly initialized with nil. This includes variable-length arrays of Objective-C object pointers. However, in the analyzer we don't zero-initialize them. We used to, but it accidentally regressed after r289618. Under ARC, the array variable's initializer within DeclStmt is an ImplicitValueInitExpr. Environment doesn't maintain any bindings for this expression kind - instead it always knows that it's a known constant (0 in our case), so it just returns the known value by calling SValBuilder::makeZeroVal() (see EnvironmentManager::getSVal(). Commit r289618 had introduced reasonable behavior of SValBuilder::makeZeroVal() for the arrays, which produces a zero-length compoundVal{}. When such value is bound to arrays, in RegionStoreManager::bindArray() "remaining" items in the array are default-initialized with zero, as in RegionStoreManager::setImplicitDefaultValue(). The similar mechanism works when an array is initialized by an initializer list that is too short, eg. int a[3] = { 1, 2 }; would result in a[2] initialized with 0. However, in case of variable-length arrays it didn't know if any more items need to be added, because, well, the length is variable. Add the default binding anyway, regardless of how many actually need to be added. We don't really care how many, because the default binding covers the whole array anyway. Differential Revision: https://reviews.llvm.org/D41478 rdar://problem/35477763 Added: cfe/trunk/test/Analysis/arc-zero-init.m Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=321290&r1=321289&r2=321290&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Thu Dec 21 10:43:02 2017 @@ -2132,9 +2132,10 @@ RegionStoreManager::bindArray(RegionBind NewB = bind(NewB, loc::MemRegionVal(ER), *VI); } - // If the init list is shorter than the array length, set the - // array default value. - if (Size.hasValue() && i < Size.getValue()) + // If the init list is shorter than the array length (or the array has + // variable length), set the array default value. Values that are already set + // are not overwritten. + if (!Size.hasValue() || i < Size.getValue()) NewB = setImplicitDefaultValue(NewB, R, ElementTy); return NewB; Added: cfe/trunk/test/Analysis/arc-zero-init.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/arc-zero-init.m?rev=321290&view=auto == --- cfe/trunk/test/Analysis/arc-zero-init.m (added) +++ cfe/trunk/test/Analysis/arc-zero-init.m Thu Dec 21 10:43:02 2017 @@ -0,0 +1,46 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -fobjc-arc %s + +#if __has_feature(objc_arc) +// expected-no-diagnostics +#endif + +@interface SomeClass +@end + +void simpleStrongPointerValue() { + SomeClass *x; + if (x) {} +#if !__has_feature(objc_arc) +// expected-warning@-2{{Branch condition evaluates to a garbage value}} +#endif +} + +void simpleArray() { + SomeClass *vlaArray[5]; + + if (vlaArray[0]) {} +#if !__has_feature(objc_arc) +// expected-warning@-2{{Branch condition evaluates to a garbage value}} +#endif +} + +void variableLengthArray() { + int count = 1; + SomeClass * vlaArray[count]; + + if (vlaArray[0]) {} +#if !__has_feature(objc_arc) + // expected-warning@-2{{Branch condition evaluates to a garbage value}} +#endif +} + +void variableLengthArrayWithExplicitStrongAttribute() { + int count = 1; + __attribute__((objc_ownership(strong))) SomeClass * vlaArray[count]; + + if (vlaArray[0]) {} +#if !__has_feature(objc_arc) + // expected-warning@-2{{Branch condition evaluates to a garbage value}} +#endif +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r326236 - [analyzer] Introduce correct lifetime extension behavior in simple cases.
Author: dergachev Date: Tue Feb 27 11:47:49 2018 New Revision: 326236 URL: http://llvm.org/viewvc/llvm-project?rev=326236&view=rev Log: [analyzer] Introduce correct lifetime extension behavior in simple cases. This patch uses the reference to MaterializeTemporaryExpr stored in the construction context since r326014 in order to model that expression correctly. When modeling MaterializeTemporaryExpr, instead of copying the raw memory contents from the sub-expression's rvalue to a completely new temporary region, that we conjure up for the lack of better options, we now have the better option to recall the region into which the object was originally constructed and declare that region to be the value of the expression, which is semantically correct. This only works when the construction context is available, which is worked on independently. The temporary region's liveness (in the sense of removeDeadBindings) is extended until the MaterializeTemporaryExpr is resolved, in order to keep the store bindings around, because it wouldn't be referenced from anywhere else in the program state. Differential Revision: https://reviews.llvm.org/D43497 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/test/Analysis/lifetime-extension.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=326236&r1=326235&r2=326236&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Tue Feb 27 11:47:49 2018 @@ -708,6 +708,19 @@ private: const LocationContext *FromLC, const LocationContext *ToLC); + /// Store the region of a C++ temporary object corresponding to a + /// CXXBindTemporaryExpr for later destruction. + static ProgramStateRef addTemporaryMaterialization( + ProgramStateRef State, const MaterializeTemporaryExpr *MTE, + const LocationContext *LC, const CXXTempObjectRegion *R); + + /// Check if all temporary materialization regions are clear for the given + /// context range (including FromLC, not including ToLC). + /// This is useful for assertions. + static bool areTemporaryMaterializationsClear(ProgramStateRef State, +const LocationContext *FromLC, +const LocationContext *ToLC); + /// Store the region returned by operator new() so that the constructor /// that follows it knew what location to initialize. The value should be /// cleared once the respective CXXNewExpr CFGStmt element is processed. Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=326236&r1=326235&r2=326236&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Feb 27 11:47:49 2018 @@ -65,6 +65,17 @@ typedef llvm::ImmutableMap, + const CXXTempObjectRegion *> +TemporaryMaterializationMap; + +// Keeps track of temporaries that will need to be materialized later. +// The StackFrameContext assures that nested calls due to inlined recursive +// functions do not interfere. +REGISTER_TRAIT_WITH_PROGRAMSTATE(TemporaryMaterializations, + TemporaryMaterializationMap) + typedef llvm::ImmutableMap, SVal> @@ -255,17 +266,35 @@ ExprEngine::createTemporaryRegionIfNeede const Expr *Init = InitWithAdjustments->skipRValueSubobjectAdjustments( CommaLHSs, Adjustments); + // Take the region for Init, i.e. for the whole object. If we do not remember + // the region in which the object originally was constructed, come up with + // a new temporary region out of thin air and copy the contents of the object + // (which are currently present in the Environment, because Init is an rvalue) + // into that region. This is not correct, but it is better than nothing. + bool FoundOriginalMaterializationRegion = false; const TypedValueRegion *TR = nullptr; if (const MaterializeTemporaryExpr *MT = dyn_cast(Result)) { -StorageDuration SD = MT->getStorageDuration(); -// If this object is bound to a reference with static storage duration, we -// put it in a different region to prevent "address leakage" warnings. -if (SD == SD_Static || SD == SD_Thr
r326238 - [CFG] NFC: Refactor ConstructionContext into a finite set of cases.
Author: dergachev Date: Tue Feb 27 12:03:35 2018 New Revision: 326238 URL: http://llvm.org/viewvc/llvm-project?rev=326238&view=rev Log: [CFG] NFC: Refactor ConstructionContext into a finite set of cases. ConstructionContext is moved into a separate translation unit and is separated into multiple classes. The "old" "raw" ConstructionContext is renamed into ConstructionContextLayer - which corresponds to the idea of building the context gradually layer-by-layer, but it isn't easy to use in the clients. Once CXXConstructExpr is reached, layers that we've gathered so far are transformed into the actual, "new-style" "flat" ConstructionContext, which is put into the CFGConstructor element and has no layers whatsoever (until it actually needs them, eg. aggregate initialization). The new-style ConstructionContext is instead presented as a variety of sub-classes that enumerate different ways of constructing an object in C++. There are 5 of these supported for now, which is around a half of what needs to be supported. The layer-by-layer buildup process is still a little bit weird, but it hides all the weirdness in one place, that sounds like a good thing. Differential Revision: https://reviews.llvm.org/D43533 Added: cfe/trunk/include/clang/Analysis/ConstructionContext.h cfe/trunk/lib/Analysis/ConstructionContext.cpp Modified: cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/lib/Analysis/CMakeLists.txt cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=326238&r1=326237&r2=326238&view=diff == --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Tue Feb 27 12:03:35 2018 @@ -38,6 +38,7 @@ namespace clang { class ASTContext; class BinaryOperator; class CFG; +class ConstructionContext; class CXXBaseSpecifier; class CXXBindTemporaryExpr; class CXXCtorInitializer; @@ -140,94 +141,6 @@ protected: CFGStmt() = default; }; -// This is bulky data for CFGConstructor which would not fit into the -// CFGElement's room (pair of pointers). Contains the information -// necessary to express what memory is being initialized by -// the construction. -class ConstructionContext { -public: - typedef llvm::PointerUnion TriggerTy; - -private: - // The construction site - the statement that triggered the construction - // for one of its parts. For instance, stack variable declaration statement - // triggers construction of itself or its elements if it's an array, - // new-expression triggers construction of the newly allocated object(s). - TriggerTy Trigger; - - // Sometimes a single trigger is not enough to describe the construction site. - // In this case we'd have a chain of "partial" construction contexts. - // Some examples: - // - A constructor within in an aggregate initializer list within a variable - // would have a construction context of the initializer list with the parent - // construction context of a variable. - // - A constructor for a temporary that needs to be both destroyed - // and materialized into an elidable copy constructor would have a - // construction context of a CXXBindTemporaryExpr with the parent - // construction context of a MaterializeTemproraryExpr. - // Not all of these are currently supported. - const ConstructionContext *Parent = nullptr; - - ConstructionContext() = default; - ConstructionContext(TriggerTy Trigger, const ConstructionContext *Parent) - : Trigger(Trigger), Parent(Parent) {} - -public: - static const ConstructionContext * - create(BumpVectorContext &C, TriggerTy Trigger, - const ConstructionContext *Parent = nullptr) { -ConstructionContext *CC = C.getAllocator().Allocate(); -return new (CC) ConstructionContext(Trigger, Parent); - } - - bool isNull() const { return Trigger.isNull(); } - - TriggerTy getTrigger() const { return Trigger; } - const ConstructionContext *getParent() const { return Parent; } - - const Stmt *getTriggerStmt() const { -return Trigger.dyn_cast(); - } - - const CXXCtorInitializer *getTriggerInit() const { -return Trigger.dyn_cast(); - } - - const MaterializeTemporaryExpr *getMaterializedTemporary() const { -// TODO: Be more careful to ensure that there's only one MTE around. -for (const ConstructionContext *CC = this; CC; CC = CC->getParent()) { - if (const auto *MTE = dyn_cast_or_null( - CC->getTriggerStmt())) { -return MTE; - } -} -return nullptr; - } - - bool isSameAsPartialContext(const ConstructionContext *Other) const { -assert(Other); -return (Trigger == Other->Trigger); - } - - // See if Other is a proper initial segment of this construction context
r326239 - [analyzer] Self-debug: Dump dynamic type info and taint with the program state.
Author: dergachev Date: Tue Feb 27 12:06:20 2018 New Revision: 326239 URL: http://llvm.org/viewvc/llvm-project?rev=326239&view=rev Log: [analyzer] Self-debug: Dump dynamic type info and taint with the program state. Useful for debugging problems with dynamic type info and taint. Differential Revision: https://reviews.llvm.org/D43657 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h cfe/trunk/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h?rev=326239&r1=326238&r2=326239&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h Tue Feb 27 12:06:20 2018 @@ -51,6 +51,9 @@ inline ProgramStateRef setDynamicTypeInf DynamicTypeInfo(NewTy, CanBeSubClassed)); } +void printDynamicTypeInfo(ProgramStateRef State, raw_ostream &Out, + const char *NL, const char *Sep); + } // ento } // clang Modified: cfe/trunk/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp?rev=326239&r1=326238&r2=326239&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp Tue Feb 27 12:06:20 2018 @@ -47,5 +47,28 @@ ProgramStateRef setDynamicTypeInfo(Progr return NewState; } +void printDynamicTypeInfo(ProgramStateRef State, raw_ostream &Out, + const char *NL, const char *Sep) { + bool First = true; + for (const auto &I : State->get()) { +if (First) { + Out << NL << "Dynamic types of regions:" << NL; + First = false; +} +const MemRegion *MR = I.first; +const DynamicTypeInfo &DTI = I.second; +Out << MR << " : "; +if (DTI.isValid()) { + Out << DTI.getType()->getPointeeType().getAsString(); + if (DTI.canBeASubClass()) { +Out << " (or its subclass)"; + } +} else { + Out << "Invalid type info"; +} +Out << NL; + } +} + } // namespace ento } // namespace clang Modified: cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp?rev=326239&r1=326238&r2=326239&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Tue Feb 27 12:06:20 2018 @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -449,6 +450,12 @@ void ProgramState::print(raw_ostream &Ou // Print out the constraints. Mgr.getConstraintManager().print(this, Out, NL, Sep); + // Print out the tracked dynamic types. + printDynamicTypeInfo(this, Out, NL, Sep); + + // Print out tainted symbols. + printTaint(Out, NL, Sep); + // Print checker-specific data. Mgr.getOwningEngine()->printState(Out, this, NL, Sep, LC); } @@ -466,7 +473,7 @@ void ProgramState::printTaint(raw_ostrea TaintMapImpl TM = get(); if (!TM.isEmpty()) -Out <<"Tainted Symbols:" << NL; +Out <<"Tainted symbols:" << NL; for (TaintMapImpl::iterator I = TM.begin(), E = TM.end(); I != E; ++I) { Out << I->first << " : " << I->second << NL; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r326240 - [analyzer] Disable constructor inlining when lifetime extending through a field.
Author: dergachev Date: Tue Feb 27 12:14:06 2018 New Revision: 326240 URL: http://llvm.org/viewvc/llvm-project?rev=326240&view=rev Log: [analyzer] Disable constructor inlining when lifetime extending through a field. Automatic destructors are missing in the CFG in situations like const int &x = C().x; For now it's better to disable construction inlining, because inlining constructors while doing nothing on destructors is very bad. Differential Revision: https://reviews.llvm.org/D43689 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp cfe/trunk/test/Analysis/lifetime-extension.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=326240&r1=326239&r2=326240&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Tue Feb 27 12:14:06 2018 @@ -65,6 +65,10 @@ public: bool IsArrayCtorOrDtor = false; /// This call is a constructor or a destructor of a temporary value. bool IsTemporaryCtorOrDtor = false; +/// This call is a constructor for a temporary that is lifetime-extended +/// by binding a smaller object within it to a reference, for example +/// 'const int &x = C().x;'. +bool IsTemporaryLifetimeExtendedViaSubobject = false; EvalCallOptions() {} }; Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=326240&r1=326239&r2=326240&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Tue Feb 27 12:14:06 2018 @@ -168,6 +168,18 @@ ExprEngine::getRegionForConstructedObjec break; } case ConstructionContext::TemporaryObjectKind: { + const auto *TOCC = cast(CC); + // See if we're lifetime-extended via our field. If so, take a note. + // Because automatic destructors aren't quite working in this case. + if (const auto *MTE = TOCC->getMaterializedTemporaryExpr()) { +if (const ValueDecl *VD = MTE->getExtendingDecl()) { + assert(VD->getType()->isReferenceType()); + if (VD->getType()->getPointeeType().getCanonicalType() != + MTE->GetTemporaryExpr()->getType().getCanonicalType()) { +CallOpts.IsTemporaryLifetimeExtendedViaSubobject = true; + } +} + } // TODO: Support temporaries lifetime-extended via static references. // They'd need a getCXXStaticTempObjectRegion(). CallOpts.IsTemporaryCtorOrDtor = true; Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=326240&r1=326239&r2=326240&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Tue Feb 27 12:14:06 2018 @@ -678,6 +678,11 @@ ExprEngine::mayInlineCallKind(const Call // the fake temporary target. if (CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) return CIP_DisallowedOnce; + + // If the temporary is lifetime-extended by binding a smaller object + // within it to a reference, automatic destructors don't work properly. + if (CallOpts.IsTemporaryLifetimeExtendedViaSubobject) +return CIP_DisallowedOnce; } break; Modified: cfe/trunk/test/Analysis/lifetime-extension.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/lifetime-extension.cpp?rev=326240&r1=326239&r2=326240&view=diff == --- cfe/trunk/test/Analysis/lifetime-extension.cpp (original) +++ cfe/trunk/test/Analysis/lifetime-extension.cpp Tue Feb 27 12:14:06 2018 @@ -39,18 +39,10 @@ void f() { const int &y = A().j[1]; // no-crash const int &z = (A().j[1], A().j[0]); // no-crash - clang_analyzer_eval(x == 1); - clang_analyzer_eval(y == 3); - clang_analyzer_eval(z == 2); -#ifdef TEMPORARIES - // expected-warning@-4{{TRUE}} - // expected-warning@-4{{TRUE}} - // expected-warning@-4{{TRUE}} -#else - // expected-warning@-8{{UNKNOWN}} - // expected-warning@-8{{UNKNOWN}} - // expected-warning@-8{{UNKNOWN}} -#endif + // FIXME: All of these should be TRUE, but constructors aren't inlined. + clang_analyzer_eval(x == 1); // expe
r326245 - [analyzer] Don't crash when dynamic type of a variable is set via placement new.
Author: dergachev Date: Tue Feb 27 12:54:40 2018 New Revision: 326245 URL: http://llvm.org/viewvc/llvm-project?rev=326245&view=rev Log: [analyzer] Don't crash when dynamic type of a variable is set via placement new. If a variable or an otherwise a concrete typed-value region is being placement-new'ed into, its dynamic type may change in arbitrary manners. And when the region is used, there may be a third type that's different from both the static and the dynamic type. It cannot be *completely* different from the dynamic type, but it may be a base class of the dynamic type - and in this case there isn't (and shouldn't be) any indication anywhere in the AST that there is a derived-to-base cast from the dynamic type to the third type. Perform a generic cast (evalCast()) from the third type to the dynamic type in this case. From the point of view of the SVal hierarchy, this would have produced non-canonical SVals if we used such generic cast in the normal case, but in this case there doesn't seem to be a better option. Differential Revision: https://reviews.llvm.org/D43659 Added: cfe/trunk/test/Analysis/new-dynamic-types.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=326245&r1=326244&r2=326245&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Tue Feb 27 12:54:40 2018 @@ -587,7 +587,15 @@ void CXXInstanceCall::getInitialStackFra // FIXME: CallEvent maybe shouldn't be directly accessing StoreManager. bool Failed; ThisVal = StateMgr.getStoreManager().attemptDownCast(ThisVal, Ty, Failed); - assert(!Failed && "Calling an incorrectly devirtualized method"); + if (Failed) { +// We might have suffered some sort of placement new earlier, so +// we're constructing in a completely unexpected storage. +// Fall back to a generic pointer cast for this-value. +const CXXMethodDecl *StaticMD = cast(getDecl()); +const CXXRecordDecl *StaticClass = StaticMD->getParent(); +QualType StaticTy = Ctx.getPointerType(Ctx.getRecordType(StaticClass)); +ThisVal = SVB.evalCast(ThisVal, Ty, StaticTy); + } } if (!ThisVal.isUnknown()) Added: cfe/trunk/test/Analysis/new-dynamic-types.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/new-dynamic-types.cpp?rev=326245&view=auto == --- cfe/trunk/test/Analysis/new-dynamic-types.cpp (added) +++ cfe/trunk/test/Analysis/new-dynamic-types.cpp Tue Feb 27 12:54:40 2018 @@ -0,0 +1,28 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -std=c++11 -verify %s + +// expected-no-diagnostics + +typedef __typeof(sizeof(int)) size_t; + +void *operator new(size_t size, void *ptr); + +struct B { + virtual void foo(); +}; + +struct D : public B { + virtual void foo() override {} +}; + +void test_ub() { + // FIXME: Potentially warn because this code is pretty weird. + B b; + new (&b) D; + b.foo(); // no-crash +} + +void test_non_ub() { + char c[sizeof(D)]; // Should be enough storage. + new (c) D; + ((B *)c)->foo(); // no-crash +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r326246 - [analyzer] Track temporaries without construction contexts for destruction.
Author: dergachev Date: Tue Feb 27 13:02:58 2018 New Revision: 326246 URL: http://llvm.org/viewvc/llvm-project?rev=326246&view=rev Log: [analyzer] Track temporaries without construction contexts for destruction. Sometimes it is not known at compile time which temporary objects will be constructed, eg. 'x ? A() : B()' or 'C() || D()'. In this case we track which temporary was constructed to know how to properly call the destructor. Once the construction context for temporaries was introduced, we moved the tracking code to the code that investigates the construction context. Bring back the old mechanism because construction contexts are not always available yet - eg. in the case where a temporary is constructed without a constructor expression, eg. returned from a function by value. The mechanism should still go away eventually. Additionally, fix a bug in the temporary cleanup code for the case when construction contexts are not available, which could lead to temporaries staying in the program state and increasing memory consumption. Differential Revision: https://reviews.llvm.org/D43666 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=326246&r1=326245&r2=326246&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Tue Feb 27 13:02:58 2018 @@ -452,6 +452,10 @@ public: ExplodedNode *Pred, ExplodedNodeSet &Dst); + void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, + ExplodedNodeSet &PreVisit, + ExplodedNodeSet &Dst); + void VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, ExplodedNodeSet &Dst); Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=326246&r1=326245&r2=326246&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Feb 27 13:02:58 2018 @@ -1089,6 +1089,34 @@ void ExprEngine::processCleanupTemporary } } +void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, + ExplodedNodeSet &PreVisit, + ExplodedNodeSet &Dst) { + // This is a fallback solution in case we didn't have a construction + // context when we were constructing the temporary. Otherwise the map should + // have been populated there. + if (!getAnalysisManager().options.includeTemporaryDtorsInCFG()) { +// In case we don't have temporary destructors in the CFG, do not mark +// the initialization - we would otherwise never clean it up. +Dst = PreVisit; +return; + } + StmtNodeBuilder StmtBldr(PreVisit, Dst, *currBldrCtx); + for (ExplodedNode *Node : PreVisit) { +ProgramStateRef State = Node->getState(); + const auto &Key = std::make_pair(BTE, Node->getStackFrame()); + +if (!State->contains(Key)) { + // FIXME: Currently the state might also already contain the marker due to + // incorrect handling of temporaries bound to default parameters; for + // those, we currently skip the CXXBindTemporaryExpr but rely on adding + // temporary destructor nodes. + State = State->set(Key, nullptr); +} +StmtBldr.generateNode(BTE, Node, State); + } +} + namespace { class CollectReachableSymbolsCallback final : public SymbolVisitor { InvalidatedSymbols Symbols; @@ -1251,7 +1279,9 @@ void ExprEngine::Visit(const Stmt *S, Ex Bldr.takeNodes(Pred); ExplodedNodeSet PreVisit; getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); - getCheckerManager().runCheckersForPostStmt(Dst, PreVisit, S, *this); + ExplodedNodeSet Next; + VisitCXXBindTemporaryExpr(cast(S), PreVisit, Next); + getCheckerManager().runCheckersForPostStmt(Dst, Next, S, *this); Bldr.addNodes(Dst); break; } @@ -2194,13 +2224,13 @@ void ExprEngine::processEndOfFunction(No Pred->getLocationContext(), Pred->getStackFrame()->getParent())); - // FIXME: We currently assert that temporaries are clear, as lifetime extended - // temporaries are not always modelled correctly. In some cases
r326247 - [analyzer] Fix trivial copy for empty objects.
Author: dergachev Date: Tue Feb 27 13:10:08 2018 New Revision: 326247 URL: http://llvm.org/viewvc/llvm-project?rev=326247&view=rev Log: [analyzer] Fix trivial copy for empty objects. The SVal for any empty C++ object is an UnknownVal. Because RegionStore does not have binding extents, binding an empty object to an UnknownVal may potentially overwrite existing bindings at the same offset. Therefore, when performing a trivial copy of an empty object, don't try to take the value of the object and bind it to the copy. Doing nothing is accurate enough, and it doesn't screw any existing bindings. Differential Revision: https://reviews.llvm.org/D43714 Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/test/Analysis/ctor.mm Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=326247&r1=326246&r2=326247&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Tue Feb 27 13:10:08 2018 @@ -42,19 +42,30 @@ void ExprEngine::performTrivialCopy(Node const CallEvent &Call) { SVal ThisVal; bool AlwaysReturnsLValue; + const CXXRecordDecl *ThisRD = nullptr; if (const CXXConstructorCall *Ctor = dyn_cast(&Call)) { assert(Ctor->getDecl()->isTrivial()); assert(Ctor->getDecl()->isCopyOrMoveConstructor()); ThisVal = Ctor->getCXXThisVal(); +ThisRD = Ctor->getDecl()->getParent(); AlwaysReturnsLValue = false; } else { assert(cast(Call.getDecl())->isTrivial()); assert(cast(Call.getDecl())->getOverloadedOperator() == OO_Equal); ThisVal = cast(Call).getCXXThisVal(); +ThisRD = cast(Call.getDecl())->getParent(); AlwaysReturnsLValue = true; } + assert(ThisRD); + if (ThisRD->isEmpty()) { +// Do nothing for empty classes. Otherwise it'd retrieve an UnknownVal +// and bind it and RegionStore would think that the actual value +// in this region at this offset is unknown. +return; + } + const LocationContext *LCtx = Pred->getLocationContext(); ExplodedNodeSet Dst; Modified: cfe/trunk/test/Analysis/ctor.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/ctor.mm?rev=326247&r1=326246&r2=326247&view=diff == --- cfe/trunk/test/Analysis/ctor.mm (original) +++ cfe/trunk/test/Analysis/ctor.mm Tue Feb 27 13:10:08 2018 @@ -729,3 +729,23 @@ namespace NoCrashOnEmptyBaseOptimization S s; } } + +namespace EmptyBaseAssign { +struct B1 {}; +struct B2 { int x; }; +struct D: public B1, public B2 { +const D &operator=(const D &d) { + *((B2 *)this) = d; + *((B1 *)this) = d; + return *this; +} +}; + +void test() { + D d1; + d1.x = 1; + D d2; + d2 = d1; + clang_analyzer_eval(d2.x == 1); // expected-warning{{TRUE}} +} +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r326249 - [analyzer] MallocChecker: Suppress false positives in shared pointers.
Author: dergachev Date: Tue Feb 27 13:19:33 2018 New Revision: 326249 URL: http://llvm.org/viewvc/llvm-project?rev=326249&view=rev Log: [analyzer] MallocChecker: Suppress false positives in shared pointers. Throw away MallocChecker warnings that occur after releasing a pointer within a destructor (or its callees) after performing C11 atomic fetch_add or fetch_sub within that destructor (or its callees). This is an indication that the destructor's class is likely a reference-counting pointer. The analyzer is not able to understand that the original reference count is usually large enough to avoid most use-after-frees. Even when the smart pointer is a local variable, we still have these false positives that this patch suppresses, because the analyzer doesn't currently support atomics well enough. Differential Revision: https://reviews.llvm.org/D43791 Added: cfe/trunk/test/Analysis/NewDelete-atomics.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=326249&r1=326248&r2=326249&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Tue Feb 27 13:19:33 2018 @@ -446,15 +446,24 @@ private: // A symbol from when the primary region should have been reallocated. SymbolRef FailedReallocSymbol; +// A C++ destructor stack frame in which memory was released. Used for +// miscellaneous false positive suppression. +const StackFrameContext *ReleaseDestructorLC; + bool IsLeak; public: MallocBugVisitor(SymbolRef S, bool isLeak = false) - : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr), IsLeak(isLeak) {} +: Sym(S), Mode(Normal), FailedReallocSymbol(nullptr), + ReleaseDestructorLC(nullptr), IsLeak(isLeak) {} + +static void *getTag() { + static int Tag = 0; + return &Tag; +} void Profile(llvm::FoldingSetNodeID &ID) const override { - static int X = 0; - ID.AddPointer(&X); + ID.AddPointer(getTag()); ID.AddPointer(Sym); } @@ -2822,6 +2831,32 @@ static SymbolRef findFailedReallocSymbol std::shared_ptr MallocChecker::MallocBugVisitor::VisitNode( const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) { + const Stmt *S = PathDiagnosticLocation::getStmt(N); + if (!S) +return nullptr; + + const LocationContext *CurrentLC = N->getLocationContext(); + + // If we find an atomic fetch_add or fetch_sub within the destructor in which + // the pointer was released (before the release), this is likely a destructor + // of a shared pointer. + // Because we don't model atomics, and also because we don't know that the + // original reference count is positive, we should not report use-after-frees + // on objects deleted in such destructors. This can probably be improved + // through better shared pointer modeling. + if (ReleaseDestructorLC) { +if (const auto *AE = dyn_cast(S)) { + AtomicExpr::AtomicOp Op = AE->getOp(); + if (Op == AtomicExpr::AO__c11_atomic_fetch_add || + Op == AtomicExpr::AO__c11_atomic_fetch_sub) { +if (ReleaseDestructorLC == CurrentLC || +ReleaseDestructorLC->isParentOf(CurrentLC)) { + BR.markInvalid(getTag(), S); +} + } +} + } + ProgramStateRef state = N->getState(); ProgramStateRef statePrev = PrevN->getState(); @@ -2830,10 +2865,6 @@ std::shared_ptr Mal if (!RS) return nullptr; - const Stmt *S = PathDiagnosticLocation::getStmt(N); - if (!S) -return nullptr; - // FIXME: We will eventually need to handle non-statement-based events // (__attribute__((cleanup))). @@ -2849,6 +2880,24 @@ std::shared_ptr Mal Msg = "Memory is released"; StackHint = new StackHintGeneratorForSymbol(Sym, "Returning; memory was released"); + + // See if we're releasing memory while inlining a destructor (or one of + // its callees). If so, enable the atomic-related suppression within that + // destructor (and all of its callees), which would kick in while visiting + // other nodes (the visit order is from the bug to the graph root). + for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) { +if (isa(LC->getDecl())) { + assert(!ReleaseDestructorLC && + "There can be only one release point!"); + ReleaseDestructorLC = LC->getCurrentStackFrame(); + // It is unlikely that releasing memory is delegated to a destructor + // inside a destructor of a shared pointer, because it's fairly hard + // to pass the information that the pointer indeed needs to be
r326258 - [analyzer] UndefinedAssignmentChecker: Better warning message in implicit ctors.
Author: dergachev Date: Tue Feb 27 14:05:55 2018 New Revision: 326258 URL: http://llvm.org/viewvc/llvm-project?rev=326258&view=rev Log: [analyzer] UndefinedAssignmentChecker: Better warning message in implicit ctors. When a class forgets to initialize a field in the constructor, and then gets copied around, a warning is emitted that the value assigned to a specific field is undefined. When the copy/move constructor is implicit (not written out in the code) but not trivial (is not a trivial memory copy, eg. because members have an explicit copy constructor), the body of such constructor is auto-generated in the AST. In this case the checker's warning message is squeezed at the top of the class declaration, and it gets hard to guess which field is at fault. Fix the warning message to include the name of the field. Differential Revision: https://reviews.llvm.org/D43798 Added: cfe/trunk/test/Analysis/implicit-ctor-undef-value.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp?rev=326258&r1=326257&r2=326258&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp Tue Feb 27 14:05:55 2018 @@ -51,17 +51,20 @@ void UndefinedAssignmentChecker::checkBi if (!N) return; - const char *str = "Assigned value is garbage or undefined"; - + static const char *const DefaultMsg = + "Assigned value is garbage or undefined"; if (!BT) -BT.reset(new BuiltinBug(this, str)); +BT.reset(new BuiltinBug(this, DefaultMsg)); // Generate a report for this bug. + llvm::SmallString<128> Str; + llvm::raw_svector_ostream OS(Str); + const Expr *ex = nullptr; while (StoreE) { if (const UnaryOperator *U = dyn_cast(StoreE)) { - str = "The expression is an uninitialized value. " + OS << "The expression is an uninitialized value. " "The computed value will also be garbage"; ex = U->getSubExpr(); @@ -71,7 +74,7 @@ void UndefinedAssignmentChecker::checkBi if (const BinaryOperator *B = dyn_cast(StoreE)) { if (B->isCompoundAssignmentOp()) { if (C.getSVal(B->getLHS()).isUndef()) { - str = "The left expression of the compound assignment is an " + OS << "The left expression of the compound assignment is an " "uninitialized value. The computed value will also be garbage"; ex = B->getLHS(); break; @@ -87,10 +90,26 @@ void UndefinedAssignmentChecker::checkBi ex = VD->getInit(); } +if (const auto *CD = +dyn_cast(C.getStackFrame()->getDecl())) { + if (CD->isImplicit()) { +for (auto I : CD->inits()) { + if (I->getInit()->IgnoreImpCasts() == StoreE) { +OS << "Value assigned to field '" << I->getMember()->getName() + << "' in implicit constructor is garbage or undefined"; +break; + } +} + } +} + break; } - auto R = llvm::make_unique(*BT, str, N); + if (OS.str().empty()) +OS << DefaultMsg; + + auto R = llvm::make_unique(*BT, OS.str(), N); if (ex) { R->addRange(ex->getSourceRange()); bugreporter::trackNullOrUndefValue(N, ex, *R); Added: cfe/trunk/test/Analysis/implicit-ctor-undef-value.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/implicit-ctor-undef-value.cpp?rev=326258&view=auto == --- cfe/trunk/test/Analysis/implicit-ctor-undef-value.cpp (added) +++ cfe/trunk/test/Analysis/implicit-ctor-undef-value.cpp Tue Feb 27 14:05:55 2018 @@ -0,0 +1,75 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -verify %s + +namespace implicit_constructor { +struct S { +public: + S() {} + S(const S &) {} +}; + +// Warning is in a weird position because the body of the constructor is +// missing. Specify which field is being assigned. +class C { // expected-warning{{Value assigned to field 'y' in implicit constructor is garbage or undefined}} + // expected-note@-1{{Value assigned to field 'y' in implicit constructor is garbage or undefined}} + int x, y; + S s; + +public: + C(): x(0) {} +}; + +void test() { + C c1; + C c2(c1); // expected-note{{Calling implicit copy constructor for 'C'}} +} +} // end namespace implicit_constructor + + +namespace explicit_constructor { +class C { + int x, y; + +public: + C(): x(0) {} + // It is not necessary to specify which field is being assigned to. + C(const C &c): +x(c.x), +y(c.y) // expected-warning{{Assigned value is garbage or undefined}} + // expected-note@-1{{
r326402 - [CFG] [analyzer] Recall that we only skip NoOp casts in construction contexts.
Author: dergachev Date: Wed Feb 28 17:09:24 2018 New Revision: 326402 URL: http://llvm.org/viewvc/llvm-project?rev=326402&view=rev Log: [CFG] [analyzer] Recall that we only skip NoOp casts in construction contexts. For now. We should also add support for ConstructorConversion casts as presented in the attached test case, but this requires more changes because AST around them seems different. The check was originally present but was accidentally lost during r326021. Differential Revision: https://reviews.llvm.org/D43840 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=326402&r1=326401&r2=326402&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Wed Feb 28 17:09:24 2018 @@ -1200,7 +1200,9 @@ void CFGBuilder::findConstructionContext } case Stmt::ImplicitCastExprClass: { auto *Cast = cast(Child); -findConstructionContexts(Layer, Cast->getSubExpr()); +// TODO: We need to support CK_ConstructorConversion, maybe other kinds? +if (Cast->getCastKind() == CK_NoOp) + findConstructionContexts(Layer, Cast->getSubExpr()); break; } case Stmt::CXXBindTemporaryExprClass: { Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=326402&r1=326401&r2=326402&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Wed Feb 28 17:09:24 2018 @@ -484,4 +484,35 @@ void referenceWithFunctionalCast() { void constructorInTernaryCondition() { const D &d = D(1) ? D(2) : D(3); } + } // end namespace temporary_object_expr_with_dtors + +namespace implicit_constructor_conversion { + +class A {}; +A get(); + +class B { +public: + B(const A &); + ~B() {} +}; + +// FIXME: Find construction context for the implicit constructor conversion. +// CHECK: void implicitConstructionConversionFromFunctionValue() +// CHECK: 1: get +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class implicit_constructor_conver +// CHECK-NEXT: 3: [B1.2]() +// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A) +// CHECK-NEXT: 5: [B1.4] +// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, class implicit_constructor_conversion::B) +// CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_convers +// CHECK-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B) +// CHECK-NEXT: 9: [B1.8] +// CHECK-NEXT:10: const implicit_constructor_conversion::B &b = get(); +// CHECK-NEXT:11: [B1.10].~B() (Implicit destructor) +void implicitConstructionConversionFromFunctionValue() { + const B &b = get(); // no-crash +} + +} // end namespace implicit_constructor_conversion ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r326405 - [analyzer] Add a checker for mmap()s which are both writable and executable.
Author: dergachev Date: Wed Feb 28 17:27:46 2018 New Revision: 326405 URL: http://llvm.org/viewvc/llvm-project?rev=326405&view=rev Log: [analyzer] Add a checker for mmap()s which are both writable and executable. This is a security check that warns when both PROT_WRITE and PROT_EXEC are set during mmap(). If mmap()ed memory is both writable and executable, it makes it easier for the attacker to execute arbitrary code when contents of this memory are compromised. Some applications require such mmap()s though, such as different sorts of JIT. Re-applied after a revert in r324167. Temporarily stays in the alpha package because it needs a better way of determining macro values that are not immediately available in the AST. Patch by David Carlier! Differential Revision: https://reviews.llvm.org/D42645 Added: cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp cfe/trunk/test/Analysis/mmap-writeexec.c Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td?rev=326405&r1=326404&r2=326405&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td Wed Feb 28 17:27:46 2018 @@ -414,6 +414,13 @@ def MallocOverflowSecurityChecker : Chec HelpText<"Check for overflows in the arguments to malloc()">, DescFile<"MallocOverflowSecurityChecker.cpp">; +// Operating systems specific PROT_READ/PROT_WRITE values is not implemented, +// the defaults are correct for several common operating systems though, +// but may need to be overridden via the related analyzer-config flags. +def MmapWriteExecChecker : Checker<"MmapWriteExec">, + HelpText<"Warn on mmap() calls that are both writable and executable">, + DescFile<"MmapWriteExecChecker.cpp">; + } // end "alpha.security" //===--===// Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt?rev=326405&r1=326404&r2=326405&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Wed Feb 28 17:27:46 2018 @@ -49,6 +49,7 @@ add_clang_library(clangStaticAnalyzerChe MallocChecker.cpp MallocOverflowSecurityChecker.cpp MallocSizeofChecker.cpp + MmapWriteExecChecker.cpp MisusedMovedObjectChecker.cpp MPI-Checker/MPIBugReporter.cpp MPI-Checker/MPIChecker.cpp Added: cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp?rev=326405&view=auto == --- cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp (added) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp Wed Feb 28 17:27:46 2018 @@ -0,0 +1,87 @@ +// MmapWriteExecChecker.cpp - Check for the prot argument -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--===// +// +// This checker tests the 3rd argument of mmap's calls to check if +// it is writable and executable in the same time. It's somehow +// an optional checker since for example in JIT libraries it is pretty common. +// +//===--===// + +#include "ClangSACheckers.h" + +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + +using namespace clang; +using namespace ento; +using llvm::APSInt; + +namespace { +class MmapWriteExecChecker : public Checker { + CallDescription MmapFn; + static int ProtWrite; + static int ProtExec; + static int ProtRead; + mutable std::unique_ptr BT; +public: + MmapWriteExecChecker() : MmapFn("mmap", 6) {} + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + int ProtExecOv; + int ProtReadOv; +}; +} + +int MmapWriteExecChecker::ProtWrite = 0x02; +int MmapWriteExecChecker::ProtExec = 0x04; +int MmapWriteExecChecker::ProtRead = 0x01; + +void MmapWriteExecChecker::checkPreCall(const CallEvent &Call, +
r326461 - [analyzer] Enable cfg-temporary-dtors by default.
Author: dergachev Date: Thu Mar 1 10:53:13 2018 New Revision: 326461 URL: http://llvm.org/viewvc/llvm-project?rev=326461&view=rev Log: [analyzer] Enable cfg-temporary-dtors by default. Don't enable c++-temp-dtor-inlining by default yet, due to this reference counting pointe problem. Otherwise the new mode seems stable and allows us to incrementally fix C++ problems in much less hacky ways. Differential Revision: https://reviews.llvm.org/D43804 Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp cfe/trunk/test/Analysis/analyzer-config.c cfe/trunk/test/Analysis/analyzer-config.cpp cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp cfe/trunk/test/Analysis/lifetime-cfg-output.cpp cfe/trunk/test/Analysis/lifetime-extension.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp?rev=326461&r1=326460&r2=326461&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp Thu Mar 1 10:53:13 2018 @@ -193,7 +193,7 @@ bool AnalyzerOptions::getBooleanOption(O bool AnalyzerOptions::includeTemporaryDtorsInCFG() { return getBooleanOption(IncludeTemporaryDtorsInCFG, "cfg-temporary-dtors", - /* Default = */ false); + /* Default = */ true); } bool AnalyzerOptions::includeImplicitDtorsInCFG() { @@ -251,7 +251,7 @@ bool AnalyzerOptions::mayInlineCXXShared bool AnalyzerOptions::mayInlineCXXTemporaryDtors() { return getBooleanOption(InlineCXXTemporaryDtors, "c++-temp-dtor-inlining", - /*Default=*/true); + /*Default=*/false); } bool AnalyzerOptions::mayInlineObjCMethod() { Modified: cfe/trunk/test/Analysis/analyzer-config.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.c?rev=326461&r1=326460&r2=326461&view=diff == --- cfe/trunk/test/Analysis/analyzer-config.c (original) +++ cfe/trunk/test/Analysis/analyzer-config.c Thu Mar 1 10:53:13 2018 @@ -16,7 +16,7 @@ void foo() { // CHECK-NEXT: cfg-lifetime = false // CHECK-NEXT: cfg-loopexit = false // CHECK-NEXT: cfg-rich-constructors = true -// CHECK-NEXT: cfg-temporary-dtors = false +// CHECK-NEXT: cfg-temporary-dtors = true // CHECK-NEXT: exploration_strategy = unexplored_first_queue // CHECK-NEXT: faux-bodies = true // CHECK-NEXT: graph-trim-interval = 1000 Modified: cfe/trunk/test/Analysis/analyzer-config.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.cpp?rev=326461&r1=326460&r2=326461&view=diff == --- cfe/trunk/test/Analysis/analyzer-config.cpp (original) +++ cfe/trunk/test/Analysis/analyzer-config.cpp Thu Mar 1 10:53:13 2018 @@ -13,7 +13,7 @@ void foo() { class Foo { public: ~Foo() {} - void baz(); + void baz() { Foo(); } void bar() { const Foo &f = Foo(); } void foo() { bar(); } }; @@ -23,13 +23,14 @@ public: // CHECK-NEXT: c++-inlining = destructors // CHECK-NEXT: c++-shared_ptr-inlining = false // CHECK-NEXT: c++-stdlib-inlining = true +// CHECK-NEXT: c++-temp-dtor-inlining = false // CHECK-NEXT: c++-template-inlining = true // CHECK-NEXT: cfg-conditional-static-initializers = true // CHECK-NEXT: cfg-implicit-dtors = true // CHECK-NEXT: cfg-lifetime = false // CHECK-NEXT: cfg-loopexit = false // CHECK-NEXT: cfg-rich-constructors = true -// CHECK-NEXT: cfg-temporary-dtors = false +// CHECK-NEXT: cfg-temporary-dtors = true // CHECK-NEXT: experimental-enable-naive-ctu-analysis = false // CHECK-NEXT: exploration_strategy = unexplored_first_queue // CHECK-NEXT: faux-bodies = true @@ -48,4 +49,4 @@ public: // CHECK-NEXT: unroll-loops = false // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 28 +// CHECK-NEXT: num-entries = 29 Modified: cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp?rev=326461&r1=326460&r2=326461&view=diff == --- cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp (original) +++ cfe/trunk/test/Analysis/inlining/temp-dtors-path-notes.cpp Thu Mar 1 10:53:13 2018 @@ -1,4 +1,4 @@ -// RUN: %clang_analyze_cc1 -analyze -analyzer-checker core -analyzer-config cfg-temporary-dtors=true -analyzer-output=text -verify %s +// RUN: %clang_analyze_cc1 -analyze -analyzer-checker core -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -analyze
r327096 - [CFG] [analyzer] Add construction context for implicit constructor conversions.
Author: dergachev Date: Thu Mar 8 17:39:59 2018 New Revision: 327096 URL: http://llvm.org/viewvc/llvm-project?rev=327096&view=rev Log: [CFG] [analyzer] Add construction context for implicit constructor conversions. Implicit constructor conversions such as A a = B() are represented by surrounding the constructor for B() with an ImplicitCastExpr of CK_ConstructorConversion kind, similarly to how explicit constructor conversions are surrounded by a CXXFunctionalCastExpr. Support this syntax pattern when extracting the construction context for the implicit constructor that performs the conversion. Differential Revision: https://reviews.llvm.org/D44051 Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/lib/Analysis/ConstructionContext.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temporaries.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=327096&r1=327095&r2=327096&view=diff == --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Thu Mar 8 17:39:59 2018 @@ -1202,8 +1202,13 @@ void CFGBuilder::findConstructionContext case Stmt::ImplicitCastExprClass: { auto *Cast = cast(Child); // TODO: We need to support CK_ConstructorConversion, maybe other kinds? -if (Cast->getCastKind() == CK_NoOp) +switch (Cast->getCastKind()) { +case CK_NoOp: +case CK_ConstructorConversion: findConstructionContexts(Layer, Cast->getSubExpr()); +default: + break; +} break; } case Stmt::CXXBindTemporaryExprClass: { Modified: cfe/trunk/lib/Analysis/ConstructionContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ConstructionContext.cpp?rev=327096&r1=327095&r2=327096&view=diff == --- cfe/trunk/lib/Analysis/ConstructionContext.cpp (original) +++ cfe/trunk/lib/Analysis/ConstructionContext.cpp Thu Mar 8 17:39:59 2018 @@ -70,8 +70,11 @@ const ConstructionContext *ConstructionC C.getAllocator().Allocate(); return new (CC) TemporaryObjectConstructionContext(BTE, MTE); } else if (const auto *MTE = dyn_cast(S)) { + // If the object requires destruction and is not lifetime-extended, + // then it must have a BTE within its MTE. assert(MTE->getType().getCanonicalType() -->getAsCXXRecordDecl()->hasTrivialDestructor()); +->getAsCXXRecordDecl()->hasTrivialDestructor() || + MTE->getStorageDuration() != SD_FullExpression); assert(TopLayer->isLast()); auto *CC = C.getAllocator().Allocate(); Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=327096&r1=327095&r2=327096&view=diff == --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original) +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Thu Mar 8 17:39:59 2018 @@ -498,20 +498,70 @@ public: ~B() {} }; -// FIXME: Find construction context for the implicit constructor conversion. +// CHECK: void implicitConstructionConversionFromTemporary() +// CHECK: 1: implicit_constructor_conversion::A() (CXXConstructExpr, [B1.3], class implicit_constructor_conversion::A) +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A) +// CHECK-NEXT: 3: [B1.2] +// CHECK-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8], class implicit_constructor_conversion::B) +// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B) +// CHECK-NEXT: 6: [B1.5] (BindTemporary) +// CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B) +// CHECK-NEXT: 8: [B1.7] +// CHECK-NEXT: 9: [B1.8] (CXXConstructExpr, [B1.10], class implicit_constructor_conversion::B) +// CHECK-NEXT:10: implicit_constructor_conversion::B b = implicit_constructor_conversion::A(); +// CHECK-NEXT:11: ~implicit_constructor_conversion::B() (Temporary object destructor) +// CHECK-NEXT:12: [B1.10].~B() (Implicit destructor) +void implicitConstructionConversionFromTemporary() { + B b = A(); +} + // CHECK: void implicitConstructionConversionFromFunctionValue() // CHECK: 1: get +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class implicit_constructor_conversion::A (*)(void)) +// CHECK-NEXT: 3: [B1.2]() +// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A) +// CHECK-NEXT: 5: [B1.4] +// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10], class implicit_constructor_conversion::B) +// CHECK-NEXT: 7: [B1.6]
r327098 - [analyzer] MmapWriteExecChecker: Add support for mprotect().
Author: dergachev Date: Thu Mar 8 17:47:24 2018 New Revision: 327098 URL: http://llvm.org/viewvc/llvm-project?rev=327098&view=rev Log: [analyzer] MmapWriteExecChecker: Add support for mprotect(). mprotect() allows setting memory access flags similarly to mmap(), causing similar security issues if these flags are needlessly broad. Patch by David Carlier! Differential Revision: https://reviews.llvm.org/D44250 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp cfe/trunk/test/Analysis/mmap-writeexec.c Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp?rev=327098&r1=327097&r2=327098&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp Thu Mar 8 17:47:24 2018 @@ -28,12 +28,13 @@ using llvm::APSInt; namespace { class MmapWriteExecChecker : public Checker { CallDescription MmapFn; + CallDescription MprotectFn; static int ProtWrite; static int ProtExec; static int ProtRead; mutable std::unique_ptr BT; public: - MmapWriteExecChecker() : MmapFn("mmap", 6) {} + MmapWriteExecChecker() : MmapFn("mmap", 6), MprotectFn("mprotect", 3) {} void checkPreCall(const CallEvent &Call, CheckerContext &C) const; int ProtExecOv; int ProtReadOv; @@ -46,8 +47,8 @@ int MmapWriteExecChecker::ProtRead = 0x void MmapWriteExecChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - if (Call.isCalled(MmapFn)) { -SVal ProtVal = Call.getArgSVal(2); + if (Call.isCalled(MmapFn) || Call.isCalled(MprotectFn)) { +SVal ProtVal = Call.getArgSVal(2); Optional ProtLoc = ProtVal.getAs(); int64_t Prot = ProtLoc->getValue().getSExtValue(); if (ProtExecOv != ProtExec) Modified: cfe/trunk/test/Analysis/mmap-writeexec.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/mmap-writeexec.c?rev=327098&r1=327097&r2=327098&view=diff == --- cfe/trunk/test/Analysis/mmap-writeexec.c (original) +++ cfe/trunk/test/Analysis/mmap-writeexec.c Thu Mar 8 17:47:24 2018 @@ -16,6 +16,7 @@ typedef __typeof(sizeof(int)) size_t; void *mmap(void *, size_t, int, int, int, long); +int mprotect(void *, size_t, int); void f1() { @@ -34,3 +35,10 @@ void f2() int prot = PROT_WRITE | PROT_EXEC; (void)callm(NULL, 1024, prot, MAP_PRIVATE | MAP_ANON, -1, 0); // expected-warning{{Both PROT_WRITE and PROT_EXEC flags are set. This can lead to exploitable memory regions, which could be overwritten with malicious code}} } + +void f3() +{ + void *p = mmap(NULL, 1024, PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); // no-warning + int m = mprotect(p, 1024, PROT_WRITE | PROT_EXEC); // expected-warning{{Both PROT_WRITE and PROT_EXEC flags are set. This can lead to exploitable memory regions, which could be overwritten with malicious code}} + (void)m; +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r327343 - [CFG] [analyzer] Add construction context to C++ return-by-value call elements.
Author: dergachev Date: Mon Mar 12 16:12:40 2018 New Revision: 327343 URL: http://llvm.org/viewvc/llvm-project?rev=327343&view=rev Log: [CFG] [analyzer] Add construction context to C++ return-by-value call elements. This patch adds a new CFGStmt sub-class, CFGCXXRecordTypedCall, which replaces the regular CFGStmt for the respective CallExpr whenever the CFG has additional information to provide regarding the lifetime of the returned value. This additional call site information is represented by a ConstructionContext (which was previously used for CFGConstructor elements) that provides references to CXXBindTemporaryExpr and MaterializeTemporaryExpr that surround the call. This corresponds to the common C++ calling convention solution of providing the target address for constructing the return value as an auxiliary implicit argument during function call. One of the use cases for such extra context at the call site would be to perform any sort of inter-procedural analysis over the CFG that involves functions returning objects by value. In this case the elidable constructor at the return site would construct the object explained by the context at the call site, and its lifetime would also be managed by the caller, not the callee. The extra context would also be useful for properly handling the return-value temporary at the call site, even if the callee is not being analyzed inter-procedurally. Differential Revision: https://reviews.llvm.org/D44120 Modified: cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp cfe/trunk/test/Analysis/cfg-rich-constructors.cpp cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=327343&r1=327342&r2=327343&view=diff == --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Mon Mar 12 16:12:40 2018 @@ -39,6 +39,7 @@ class ASTContext; class BinaryOperator; class CFG; class ConstructionContext; +class TemporaryObjectConstructionContext; class CXXBaseSpecifier; class CXXBindTemporaryExpr; class CXXCtorInitializer; @@ -65,8 +66,9 @@ public: // stmt kind Statement, Constructor, +CXXRecordTypedCall, STMT_BEGIN = Statement, -STMT_END = Constructor, +STMT_END = CXXRecordTypedCall, // dtor kind AutomaticObjectDtor, DeleteDtor, @@ -158,10 +160,6 @@ public: return static_cast(Data2.getPointer()); } - QualType getType() const { -return cast(getStmt())->getType(); - } - private: friend class CFGElement; @@ -172,6 +170,46 @@ private: } }; +/// CFGCXXRecordTypedCall - Represents a function call that returns a C++ object +/// by value. This, like constructor, requires a construction context, which +/// will always be that of a temporary object - usually consumed by an elidable +/// constructor. For such value-typed calls the ReturnedValueConstructionContext +/// of their return value is naturally complemented by the +/// TemporaryObjectConstructionContext at the call site (here). In C such +/// tracking is not necessary because no additional effort is required for +/// destroying the object or modeling copy elision. Like CFGConstructor, this is +/// for now only used by the analyzer's CFG. +class CFGCXXRecordTypedCall : public CFGStmt { +public: + /// Returns true when call expression \p CE needs to be represented + /// by CFGCXXRecordTypedCall, as opposed to a regular CFGStmt. + static bool isCXXRecordTypedCall(CallExpr *CE) { +return CE->getType().getCanonicalType()->getAsCXXRecordDecl(); + } + + explicit CFGCXXRecordTypedCall(CallExpr *CE, + const TemporaryObjectConstructionContext *C) + : CFGStmt(CE, CXXRecordTypedCall) { +assert(isCXXRecordTypedCall(CE)); +assert(C); +Data2.setPointer(const_cast(C)); + } + + const TemporaryObjectConstructionContext *getConstructionContext() const { +return static_cast( +Data2.getPointer()); + } + +private: + friend class CFGElement; + + CFGCXXRecordTypedCall() = default; + + static bool isKind(const CFGElement &E) { +return E.getKind() == CXXRecordTypedCall; + } +}; + /// CFGInitializer - Represents C++ base or member initializer from /// constructor's initialization list. class CFGInitializer : public CFGElement { @@ -840,6 +878,12 @@ public: Elements.push_back(CFGConstructor(CE, CC), C); } + void appendCXXRecordTypedCall(CallExpr *CE, +const TemporaryObjectConstructionContext *CC, +BumpVectorContext &C) { +Elements.push_back(CFGCXXRecordTypedCall(CE, CC), C); + } + void appendInitializer(CXXCtorInitializer *initializ
r327345 - [analyzer] Destroy and lifetime-extend inlined function return values properly.
Author: dergachev Date: Mon Mar 12 16:22:35 2018 New Revision: 327345 URL: http://llvm.org/viewvc/llvm-project?rev=327345&view=rev Log: [analyzer] Destroy and lifetime-extend inlined function return values properly. This patch uses the newly added CFGCXXRecordTypedCall element at the call site of the caller to construct the return value within the callee directly into the caller's stack frame. This way it is also capable of populating the temporary destructor and lifetime extension maps for the temporary, which allows temporary destructors and lifetime extension to work correctly. This patch does not affect temporaries that were returned from conservatively evaluated functions. Differential Revision: https://reviews.llvm.org/D44124 Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/test/Analysis/lifetime-extension.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=327345&r1=327344&r2=327345&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Mon Mar 12 16:22:35 2018 @@ -197,16 +197,19 @@ ExprEngine::getRegionForConstructedObjec return MRMgr.getCXXTempObjectRegion(CE, LCtx); } case ConstructionContext::ReturnedValueKind: { - // TODO: We should construct into a CXXBindTemporaryExpr or a - // MaterializeTemporaryExpr around the call-expression on the previous - // stack frame. Currently we re-bind the temporary to the correct region - // later, but that's not semantically correct. This of course does not - // apply when we're in the top frame. But if we are in an inlined - // function, we should be able to take the call-site CFG element, - // and it should contain (but right now it wouldn't) some sort of - // construction context that'd give us the right temporary expression. + // The temporary is to be managed by the parent stack frame. + // So build it in the parent stack frame if we're not in the + // top frame of the analysis. + // TODO: What exactly happens when we are? Does the temporary object live + // long enough in the region store in this case? Would checkers think + // that this object immediately goes out of scope? + const LocationContext *TempLCtx = LCtx; + if (const LocationContext *CallerLCtx = + LCtx->getCurrentStackFrame()->getParent()) { +TempLCtx = CallerLCtx; + } CallOpts.IsTemporaryCtorOrDtor = true; - return MRMgr.getCXXTempObjectRegion(CE, LCtx); + return MRMgr.getCXXTempObjectRegion(CE, TempLCtx); } } } @@ -262,6 +265,7 @@ void ExprEngine::VisitCXXConstructExpr(c assert(C || getCurrentCFGElement().getAs()); const ConstructionContext *CC = C ? C->getConstructionContext() : nullptr; + bool IsReturnedIntoParentStackFrame = false; const CXXBindTemporaryExpr *BTE = nullptr; const MaterializeTemporaryExpr *MTE = nullptr; @@ -269,25 +273,44 @@ void ExprEngine::VisitCXXConstructExpr(c case CXXConstructExpr::CK_Complete: { Target = getRegionForConstructedObject(CE, Pred, CC, CallOpts); -// In case of temporary object construction, extract data necessary for -// destruction and lifetime extension. -if (const auto *TCC = -dyn_cast_or_null(CC)) { - assert(CallOpts.IsTemporaryCtorOrDtor); - assert(!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion); - if (AMgr.getAnalyzerOptions().includeTemporaryDtorsInCFG()) { -BTE = TCC->getCXXBindTemporaryExpr(); -MTE = TCC->getMaterializedTemporaryExpr(); -if (!BTE) { - // FIXME: lifetime extension for temporaries without destructors - // is not implemented yet. - MTE = nullptr; +if (CC) { + // In case of temporary object construction, extract data necessary for + // destruction and lifetime extension. + const auto *TCC = dyn_cast(CC); + + // If the temporary is being returned from the function, it will be + // destroyed or lifetime-extended in the caller stack frame. + if (const auto *RCC = dyn_cast(CC)) { +const StackFrameContext *SFC = LCtx->getCurrentStackFrame(); +assert(SFC); +if (SFC->getParent()) { + IsReturnedIntoParentStackFrame = true; + const CFGElement &CallElem = + (*SFC->getCallSiteBlock())[SFC->getIndex()]; + if (auto RTCElem = CallElem.getAs()) { +TCC = cast( +RTCElem->getConstructionContext()); + } } -if (MTE && MTE->getStorageDuration() != SD_FullExpression) { - // If the temporary is lifetime-extended, don't save the BTE, - // because we don't need a temporary destructor, but an automatic - /
r327347 - [analyzer] NFC: Move the code for setting temp object lifetime into method.
Author: dergachev Date: Mon Mar 12 16:27:52 2018 New Revision: 327347 URL: http://llvm.org/viewvc/llvm-project?rev=327347&view=rev Log: [analyzer] NFC: Move the code for setting temp object lifetime into method. Differential Revision: https://reviews.llvm.org/D44129 Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=327347&r1=327346&r2=327347&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Mon Mar 12 16:27:52 2018 @@ -774,6 +774,14 @@ private: const LocationContext *FromLC, const LocationContext *ToLC); + /// Adds an initialized temporary and/or a materialization, whichever is + /// necessary, by looking at the whole construction context. Handles + /// function return values, which need the construction context of the parent + /// stack frame, automagically. + ProgramStateRef addAllNecessaryTemporaryInfo( + ProgramStateRef State, const ConstructionContext *CC, + const LocationContext *LC, const MemRegion *R); + /// Store the region returned by operator new() so that the constructor /// that follows it knew what location to initialize. The value should be /// cleared once the respective CXXNewExpr CFGStmt element is processed. Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=327347&r1=327346&r2=327347&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Mon Mar 12 16:27:52 2018 @@ -31,6 +31,7 @@ #include "clang/AST/Type.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/ConstructionContext.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" @@ -449,6 +450,65 @@ bool ExprEngine::areTemporaryMaterializa return true; } +ProgramStateRef ExprEngine::addAllNecessaryTemporaryInfo( +ProgramStateRef State, const ConstructionContext *CC, +const LocationContext *LC, const MemRegion *R) { + const CXXBindTemporaryExpr *BTE = nullptr; + const MaterializeTemporaryExpr *MTE = nullptr; + const LocationContext *TempLC = LC; + + if (CC) { +// In case of temporary object construction, extract data necessary for +// destruction and lifetime extension. +const auto *TCC = dyn_cast(CC); + +// If the temporary is being returned from the function, it will be +// destroyed or lifetime-extended in the caller stack frame. +if (const auto *RCC = dyn_cast(CC)) { + const StackFrameContext *SFC = LC->getCurrentStackFrame(); + assert(SFC); + if (SFC->getParent()) { +TempLC = SFC->getParent(); +const CFGElement &CallElem = +(*SFC->getCallSiteBlock())[SFC->getIndex()]; +if (auto RTCElem = CallElem.getAs()) { + TCC = cast( + RTCElem->getConstructionContext()); +} + } +} +if (TCC) { + if (AMgr.getAnalyzerOptions().includeTemporaryDtorsInCFG()) { +BTE = TCC->getCXXBindTemporaryExpr(); +MTE = TCC->getMaterializedTemporaryExpr(); +if (!BTE) { + // FIXME: Lifetime extension for temporaries without destructors + // is not implemented yet. + MTE = nullptr; +} +if (MTE && MTE->getStorageDuration() != SD_FullExpression) { + // If the temporary is lifetime-extended, don't save the BTE, + // because we don't need a temporary destructor, but an automatic + // destructor. + BTE = nullptr; +} + } +} + +if (BTE) { + State = addInitializedTemporary(State, BTE, TempLC, + cast(R)); +} + +if (MTE) { + State = addTemporaryMaterialization(State, MTE, TempLC, + cast(R)); +} + } + + return State; +} + ProgramStateRef ExprEngine::setCXXNewAllocatorValue(ProgramStateRef State, const CXXNewExpr *CNE, Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=327347&r1=327346&r2=327347&view=diff ==