r339087 - [analyzer] NFC: Document that we support implicit argument constructors.

2018-08-06 Thread Artem Dergachev via cfe-commits
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().

2018-08-06 Thread Artem Dergachev via cfe-commits
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.

2018-08-14 Thread Artem Dergachev via cfe-commits
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.

2018-08-14 Thread Artem Dergachev via cfe-commits
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.

2018-08-14 Thread Artem Dergachev via cfe-commits
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()...".

2018-05-14 Thread Artem Dergachev via cfe-commits
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.

2018-05-15 Thread Artem Dergachev via cfe-commits
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().

2018-05-25 Thread Artem Dergachev via cfe-commits
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.

2017-09-26 Thread Artem Dergachev via cfe-commits
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.

2017-09-27 Thread Artem Dergachev via cfe-commits
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.

2017-09-27 Thread Artem Dergachev via cfe-commits
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.

2017-09-27 Thread Artem Dergachev via cfe-commits
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.

2017-10-04 Thread Artem Dergachev via cfe-commits
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.

2017-10-05 Thread Artem Dergachev via cfe-commits
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.

2017-10-10 Thread Artem Dergachev via cfe-commits
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.

2017-10-10 Thread Artem Dergachev via cfe-commits
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.

2017-10-10 Thread Artem Dergachev via cfe-commits
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.

2017-10-13 Thread Artem Dergachev via cfe-commits
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.

2017-10-13 Thread Artem Dergachev via cfe-commits
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.

2017-10-13 Thread Artem Dergachev via cfe-commits
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.

2018-08-29 Thread Artem Dergachev via cfe-commits
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.

2018-08-29 Thread Artem Dergachev via cfe-commits
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.

2018-08-29 Thread Artem Dergachev via cfe-commits
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.

2018-08-29 Thread Artem Dergachev via cfe-commits
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.

2018-08-29 Thread Artem Dergachev via cfe-commits
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.

2018-08-30 Thread Artem Dergachev via cfe-commits
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.

2018-07-23 Thread Artem Dergachev via cfe-commits
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.

2018-07-23 Thread Artem Dergachev via cfe-commits
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.

2018-07-30 Thread Artem Dergachev via cfe-commits
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

2018-07-30 Thread Artem Dergachev via cfe-commits
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.

2018-07-31 Thread Artem Dergachev via cfe-commits
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().

2018-07-31 Thread Artem Dergachev via cfe-commits
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.

2018-07-31 Thread Artem Dergachev via cfe-commits
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++.

2018-07-31 Thread Artem Dergachev via cfe-commits
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.

2018-07-31 Thread Artem Dergachev via cfe-commits
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.

2018-07-31 Thread Artem Dergachev via cfe-commits
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.

2018-07-31 Thread Artem Dergachev via cfe-commits
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.

2018-07-31 Thread Artem Dergachev via cfe-commits
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.

2018-02-08 Thread Artem Dergachev via cfe-commits
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.

2018-02-08 Thread Artem Dergachev via cfe-commits
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.

2018-02-08 Thread Artem Dergachev via cfe-commits
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.

2018-02-08 Thread Artem Dergachev via cfe-commits
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.

2018-02-08 Thread Artem Dergachev via cfe-commits
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.

2018-02-09 Thread Artem Dergachev via cfe-commits
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.

2018-02-09 Thread Artem Dergachev via cfe-commits
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.

2018-02-09 Thread Artem Dergachev via cfe-commits
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.

2018-02-09 Thread Artem Dergachev via cfe-commits
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.

2018-02-09 Thread Artem Dergachev via cfe-commits
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.

2018-02-09 Thread Artem Dergachev via cfe-commits
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.

2018-02-09 Thread Artem Dergachev via cfe-commits
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.

2018-02-09 Thread Artem Dergachev via cfe-commits
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.

2018-02-12 Thread Artem Dergachev via cfe-commits
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.

2018-02-14 Thread Artem Dergachev via cfe-commits
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.

2018-02-14 Thread Artem Dergachev via cfe-commits
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.

2018-02-14 Thread Artem Dergachev via cfe-commits
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.

2018-02-14 Thread Artem Dergachev via cfe-commits
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.

2018-02-14 Thread Artem Dergachev via cfe-commits
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().

2018-02-15 Thread Artem Dergachev via cfe-commits
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.

2018-02-15 Thread Artem Dergachev via cfe-commits
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.

2018-02-15 Thread Artem Dergachev via cfe-commits
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.

2018-02-15 Thread Artem Dergachev via cfe-commits
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.

2018-02-23 Thread Artem Dergachev via cfe-commits
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.

2018-02-23 Thread Artem Dergachev via cfe-commits
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.

2018-02-23 Thread Artem Dergachev via cfe-commits
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.

2018-02-23 Thread Artem Dergachev via cfe-commits
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.

2018-02-23 Thread Artem Dergachev via cfe-commits
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.

2018-02-23 Thread Artem Dergachev via cfe-commits
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.

2018-02-23 Thread Artem Dergachev via cfe-commits
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.

2018-02-23 Thread Artem Dergachev via cfe-commits
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.

2018-02-26 Thread Artem Dergachev via cfe-commits
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.

2017-05-29 Thread Artem Dergachev via cfe-commits
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.

2017-05-29 Thread Artem Dergachev via cfe-commits
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.

2017-05-29 Thread Artem Dergachev via cfe-commits
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.

2017-05-29 Thread Artem Dergachev via cfe-commits
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.

2017-06-05 Thread Artem Dergachev via cfe-commits
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.

2017-06-05 Thread Artem Dergachev via cfe-commits
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.

2017-06-12 Thread Artem Dergachev via cfe-commits
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.

2017-06-21 Thread Artem Dergachev via cfe-commits
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.

2017-06-21 Thread Artem Dergachev via cfe-commits
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.

2017-12-19 Thread Artem Dergachev via cfe-commits
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.

2017-12-19 Thread Artem Dergachev via cfe-commits
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.

2017-12-19 Thread Artem Dergachev via cfe-commits
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.

2017-12-21 Thread Artem Dergachev via cfe-commits
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.

2018-02-27 Thread Artem Dergachev via cfe-commits
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.

2018-02-27 Thread Artem Dergachev via cfe-commits
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.

2018-02-27 Thread Artem Dergachev via cfe-commits
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.

2018-02-27 Thread Artem Dergachev via cfe-commits
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.

2018-02-27 Thread Artem Dergachev via cfe-commits
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.

2018-02-27 Thread Artem Dergachev via cfe-commits
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.

2018-02-27 Thread Artem Dergachev via cfe-commits
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.

2018-02-27 Thread Artem Dergachev via cfe-commits
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.

2018-02-27 Thread Artem Dergachev via cfe-commits
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.

2018-02-28 Thread Artem Dergachev via cfe-commits
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.

2018-02-28 Thread Artem Dergachev via cfe-commits
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.

2018-03-01 Thread Artem Dergachev via cfe-commits
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.

2018-03-08 Thread Artem Dergachev via cfe-commits
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().

2018-03-08 Thread Artem Dergachev via cfe-commits
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.

2018-03-12 Thread Artem Dergachev via cfe-commits
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.

2018-03-12 Thread Artem Dergachev via cfe-commits
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.

2018-03-12 Thread Artem Dergachev via cfe-commits
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
==

  1   2   3   4   5   6   7   8   9   10   >