[PATCH] D49438: [analyzer][UninitializedObjectChecker] New flag to turn off dereferencing

2018-08-06 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

I think what pointer chasing should do, is check whether that pointer owns the 
pointee. In that case, it should be fine to analyze it. Do you mind if I put a 
TODO around flag's description stating that this should be implemented and 
pointer chasing should be enabled by default once that's done?


https://reviews.llvm.org/D49438



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49438: [analyzer][UninitializedObjectChecker] New flag to turn off dereferencing

2018-08-06 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

In https://reviews.llvm.org/D49438#1189772, @george.karpenkov wrote:

> > I think what pointer chasing should do, is check whether that pointer owns 
> > the pointee
>
> But ownership is a convention, and it's not always deducible from a codebase.


How about the following case:

  struct A {
struct B {
  int b;
};
std::unique_ptr ptr;
A() : ptr(new B) {}
  };
  
  A a;

Here, `a->ptr->b` is clearly uninitialized, and I think it's fine to assume in 
most cases that no other pointer points to it right after `a`'s construction.

> I think of those as two separate checks, and I think we should only talk 
> about enabling the pointer-chasing after we had established that just 
> checking for uninitialized fields finds lots of valid bugs (and we can only 
> do that after it gets enabled for many projects)

I think in the earlier case `*this->ptr` should be regarded as a regular field, 
and it could be analyzed without fear of spamming too many reports. Currently 
the biggest problem is that many objects could contain references to the same 
object:

  struct A { int x; };
  struct B {
A &a;
B(A &a) : a(a) {}
  };
  struct C {
A &a;
C(A &a) : a(a) {}
  };
  
  A a;
  B b(a);
  C c(a); // a.x reported twice


https://reviews.llvm.org/D49438



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49438: [analyzer][UninitializedObjectChecker] New flag to turn off dereferencing

2018-08-06 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

If we ignore references, check whether the pointee was constructed within the 
constructor, and maybe add some other clever heuristics, I'm very much in favor 
of enabling pointer chasing by enabled. But I totally support disabling it for 
now.


https://reviews.llvm.org/D49438



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49438: [analyzer][UninitializedObjectChecker] New flag to turn off dereferencing

2018-08-06 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

I'll be back in office tomorrow, about ~13 hours later. But feel free to commit 
it on my behalf if it's urgent.


https://reviews.llvm.org/D49438



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49438: [analyzer][UninitializedObjectChecker] New flag to turn off dereferencing

2018-08-07 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 159486.
Szelethus added a comment.

Added the TODO we were discussing.


https://reviews.llvm.org/D49438

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp
  test/Analysis/cxx-uninitialized-object-no-dereference.cpp
  test/Analysis/cxx-uninitialized-object-notes-as-warnings.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -1,6 +1,11 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s
-
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN:   -std=c++11 -verify  %s
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN:   -std=c++11 -verify  %s
 
 //===--===//
 // Default constructor test.
Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -1,6 +1,11 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s
-
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN:   -std=c++11 -verify  %s
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN:   -std=c++11 -verify  %s
 
 //===--===//
 // Concrete location tests.
Index: test/Analysis/cxx-uninitialized-object-notes-as-warnings.cpp
===
--- test/Analysis/cxx-uninitialized-object-notes-as-warnings.cpp
+++ test/Analysis/cxx-uninitialized-object-notes-as-warnings.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN:   -std=c++11 -verify %s
 
 class NotesAsWarningsTest {
   int a;
Index: test/Analysis/cxx-uninitialized-object-no-dereference.cpp
===
--- /dev/null
+++ test/Analysis/cxx-uninitialized-object-no-dereference.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -std=c++11 -DPEDANTIC -verify %s
+
+class UninitPointerTest {
+  int *ptr; // expected-note{{uninitialized pointer 'this->ptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+public:
+  UninitPointerTest() {} // expected-warning{{1 uninitialized field}}
+};
+
+void fUninitPointerTest() {
+  UninitPointerTest();
+}
+
+class UninitPointeeTest {
+  int *ptr; // no-note
+  int dontGetFilteredByNonPedanticMode = 0;
+
+public:
+  UninitPointeeTest(int *ptr) : ptr(ptr) {} // no-warning
+};
+
+void fUninitPointeeTest() {
+  int a;
+  UninitPointeeTest t(&a);
+}
Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -

[PATCH] D49438: [analyzer][UninitializedObjectChecker] New flag to turn off dereferencing

2018-08-07 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339135: [analyzer][UninitializedObjectChecker] New flag to 
turn off dereferencing (authored by Szelethus, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D49438

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp
  test/Analysis/cxx-uninitialized-object-no-dereference.cpp
  test/Analysis/cxx-uninitialized-object-notes-as-warnings.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -1,6 +1,11 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s
-
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN:   -std=c++11 -verify  %s
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN:   -std=c++11 -verify  %s
 
 //===--===//
 // Concrete location tests.
Index: test/Analysis/cxx-uninitialized-object-no-dereference.cpp
===
--- test/Analysis/cxx-uninitialized-object-no-dereference.cpp
+++ test/Analysis/cxx-uninitialized-object-no-dereference.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -std=c++11 -DPEDANTIC -verify %s
+
+class UninitPointerTest {
+  int *ptr; // expected-note{{uninitialized pointer 'this->ptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+public:
+  UninitPointerTest() {} // expected-warning{{1 uninitialized field}}
+};
+
+void fUninitPointerTest() {
+  UninitPointerTest();
+}
+
+class UninitPointeeTest {
+  int *ptr; // no-note
+  int dontGetFilteredByNonPedanticMode = 0;
+
+public:
+  UninitPointeeTest(int *ptr) : ptr(ptr) {} // no-warning
+};
+
+void fUninitPointeeTest() {
+  int a;
+  UninitPointeeTest t(&a);
+}
Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -1,6 +1,11 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s
-
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN:   -std=c++11 -verify  %s
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN:   -std=c++11 -verify  %s
 
 //===--===//
 // Default constructor test.
Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN: -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN: -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
+// RUN: -std=c++11 -verify  %s
 
 //===--===//
 // Non-polymorphic inheritance tests
Index: test/Analysis/cxx-uninitialized-object-notes-as-warnings.cpp
===
--- test/Analysis/cxx-uninitialized-object-notes-as-warnings.cp

[PATCH] D48436: [analyzer][UninitializedObjectChecker] Fixed a false negative by no longer filtering out certain constructor calls

2018-08-07 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

Polite ping :)


https://reviews.llvm.org/D48436



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48436: [analyzer][UninitializedObjectChecker] Fixed a false negative by no longer filtering out certain constructor calls

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

In https://reviews.llvm.org/D48436#1191458, @NoQ wrote:

> Ok, let's commit this and see how to fix it later.


Thanks! ^-^

> I still think it's more important to come up with clear rules of who is 
> responsible for initializing fields than making sure our warnings are 
> properly grouped together.

I'll admit that the main reason why I only added a TODO about this issue and 
delayed it for later is that I'm a little unsure about some details myself. I 
spent serious effort on some ideas, which I later realized didn't work out too 
well, so I'm looking for a solid solution on some issues (like base class 
handling) that is both efficient to a degree and makes sense from a user 
standpoint before writing a doc file of some sort.

Currently, I'm working on refactoring the checker (which is why I didn't update 
some of my patches, as those changes would become obsolete), which will greatly 
increase readability and reliability (let's face it, the code about pointer 
chasing is a spaghetti).

>> [...]ideally we wouldn't like to have a warning for an object (`t`) and a 
>> separate warning for it's field (`t.bptr.x`)[...]
> 
> I don't quite understand this. How would the first warning look like? What 
> would it warn about?

I'm afraid I explained my thoughts very poorly. I have a much better grasp on 
this issue now, and I have a very good solution in testing. I'll upload a new 
diff during the week that will clarify this.
Here's what I meant with the correct code:

  struct DynTBase {
// This is the line I meant but forgot to add.
int x; // expected-note{{uninitialized field 'this->bptr->x'}}
  };
  struct DynTDerived : DynTBase {
// TODO: we'd expect the note: {{uninitialized field 'this->bptr->y'}}
int y; // no-note
  };
  
  struct DynamicTypeTest {
DynTBase *bptr;

int i = 0;
  
DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // expected-warning{{1 
uninitialized field}}
  };
  
  void f() {
DynTDerived d;
DynamicTypeTest t(&d);
  };

In this one, note that the constructed object `t` has two uninitialized fields, 
`t.bptr->x` and `t.bptr->y`. Currently, my checker misses the second one. The 
first one gets picked up rather easily, but then the problem arises about how 
do we deal with `t.bptr->y`. I proposed two ideas:

1. In `isNonUnionUninit`, obtain the dynamic type of the object we're 
analyzing. This is the easier solution, as the current implementation 
explicitly checks each base. This would result in one warning with a note for 
each field.
2. Change `willObjectBeAnalyzedLater` so that bases are analyzed on their own, 
and eliminate checking bases explicitly 
(https://reviews.llvm.org/D45532#inline-415396). The checker won't run when `d` 
is constructed, because it has a default ctor, but will run after `t`. How do 
we catch `t.bptr->y?` If we don't analyze bases explicitly, we can't just 
obtain the dynamic type in `isNonUnionUninit`, because then we'd miss 
`t.bptr->x`. If we decide that for fields we will explicitly check bases, that 
would be inconsistent, because in `t`s case we would analyze base classes on 
their own (if it had any), but we wouldn't for its fields. As you said,

> With that i guess you'll still have to deep-scan fields and bases, which 
> prevents us from simplifying our code.

I really just wanted to emphasize the point that I need more time to figure 
this out.




Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:669-671
+  Optional CurrentObject = getObjectVal(Ctor, 
Context);
+  if (!CurrentObject)
+return false;

NoQ wrote:
> All uses of `getObjectVal` so far are followed by retrieving the parent 
> region from the `LazyCompoundVal`. Why do you need to obtain the 
> `LazyCompoundVal` in the first place, i.e. do the second `getSVal` "for 
> '*this'" in `getObjectVal`? Why not just operate over the this-region on the 
> current Store? I think there isn't even a guarantee that these two regions 
> are the same. Like, in this case they probably will be the same, but we 
> shouldn't rely on that.
Fair point, that part was written when I knew very little about how these 
things worked. I'll add a TODO to get that fixed before commiting.


https://reviews.llvm.org/D48436



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48436: [analyzer][UninitializedObjectChecker] Fixed a false negative by no longer filtering out certain constructor calls

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 159687.
Szelethus added a comment.

Added a TODO.


https://reviews.llvm.org/D48436

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -1040,13 +1040,12 @@
 // While a singleton would make more sense as a static variable, that would zero
 // initialize all of its fields, hence the not too practical implementation.
 struct Singleton {
-  // TODO: we'd expect the note: {{uninitialized field 'this->i'}}
-  int i; // no-note
+  int i; // expected-note{{uninitialized field 'this->i'}}
+  int dontGetFilteredByNonPedanticMode = 0;
 
   Singleton() {
 assert(!isInstantiated);
-// TODO: we'd expect the warning: {{1 uninitialized field}}
-isInstantiated = true; // no-warning
+isInstantiated = true; // expected-warning{{1 uninitialized field}}
   }
 
   ~Singleton() {
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -225,12 +225,16 @@
 
 /// Returns the object that was constructed by CtorDecl, or None if that isn't
 /// possible.
+// TODO: Refactor this function so that it returns the constructed object's
+// region.
 static Optional
 getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
 
-/// Checks whether the constructor under checking is called by another
-/// constructor.
-static bool isCalledByConstructor(const CheckerContext &Context);
+/// Checks whether the object constructed by \p Ctor will be analyzed later
+/// (e.g. if the object is a field of another object, in which case we'd check
+/// it multiple times).
+static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
+   CheckerContext &Context);
 
 /// Returns whether FD can be (transitively) dereferenced to a void pointer type
 /// (void*, void**, ...). The type of the region behind a void pointer isn't
@@ -273,7 +277,7 @@
 return;
 
   // This avoids essentially the same error being reported multiple times.
-  if (isCalledByConstructor(Context))
+  if (willObjectBeAnalyzedLater(CtorDecl, Context))
 return;
 
   Optional Object = getObjectVal(CtorDecl, Context);
@@ -433,8 +437,8 @@
   }
 
   // Checking bases.
-  // FIXME: As of now, because of `isCalledByConstructor`, objects whose type
-  // is a descendant of another type will emit warnings for uninitalized
+  // FIXME: As of now, because of `willObjectBeAnalyzedLater`, objects whose
+  // type is a descendant of another type will emit warnings for uninitalized
   // inherited members.
   // This is not the only way to analyze bases of an object -- if we didn't
   // filter them out, and didn't analyze the bases, this checker would run for
@@ -661,18 +665,32 @@
   return Object.getAs();
 }
 
-// TODO: We should also check that if the constructor was called by another
-// constructor, whether those two are in any relation to one another. In it's
-// current state, this introduces some false negatives.
-static bool isCalledByConstructor(const CheckerContext &Context) {
-  const LocationContext *LC = Context.getLocationContext()->getParent();
+static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
+   CheckerContext &Context) {
 
-  while (LC) {
-if (isa(LC->getDecl()))
-  return true;
+  Optional CurrentObject = getObjectVal(Ctor, Context);
+  if (!CurrentObject)
+return false;
+
+  const LocationContext *LC = Context.getLocationContext();
+  while ((LC = LC->getParent())) {
+
+// If \p Ctor was called by another constructor.
+const auto *OtherCtor = dyn_cast(LC->getDecl());
+if (!OtherCtor)
+  continue;
 
-LC = LC->getParent();
+Optional OtherObject =
+getObjectVal(OtherCtor, Context);
+if (!OtherObject)
+  continue;
+
+// If the CurrentObject is a subregion of OtherObject, it will be analyzed
+// during the analysis of OtherObject.
+if (CurrentObject->getRegion()->isSubRegionOf(OtherObject->getRegion()))
+  return true;
   }
+
   return false;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48436: [analyzer][UninitializedObjectChecker] Fixed a false negative by no longer filtering out certain constructor calls

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339237: [analyzer][UninitializedObjectChecker] Fixed a false 
negative by no longer… (authored by Szelethus, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D48436

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -225,12 +225,16 @@
 
 /// Returns the object that was constructed by CtorDecl, or None if that isn't
 /// possible.
+// TODO: Refactor this function so that it returns the constructed object's
+// region.
 static Optional
 getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
 
-/// Checks whether the constructor under checking is called by another
-/// constructor.
-static bool isCalledByConstructor(const CheckerContext &Context);
+/// Checks whether the object constructed by \p Ctor will be analyzed later
+/// (e.g. if the object is a field of another object, in which case we'd check
+/// it multiple times).
+static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
+   CheckerContext &Context);
 
 /// Returns whether FD can be (transitively) dereferenced to a void pointer type
 /// (void*, void**, ...). The type of the region behind a void pointer isn't
@@ -273,7 +277,7 @@
 return;
 
   // This avoids essentially the same error being reported multiple times.
-  if (isCalledByConstructor(Context))
+  if (willObjectBeAnalyzedLater(CtorDecl, Context))
 return;
 
   Optional Object = getObjectVal(CtorDecl, Context);
@@ -433,8 +437,8 @@
   }
 
   // Checking bases.
-  // FIXME: As of now, because of `isCalledByConstructor`, objects whose type
-  // is a descendant of another type will emit warnings for uninitalized
+  // FIXME: As of now, because of `willObjectBeAnalyzedLater`, objects whose
+  // type is a descendant of another type will emit warnings for uninitalized
   // inherited members.
   // This is not the only way to analyze bases of an object -- if we didn't
   // filter them out, and didn't analyze the bases, this checker would run for
@@ -661,18 +665,32 @@
   return Object.getAs();
 }
 
-// TODO: We should also check that if the constructor was called by another
-// constructor, whether those two are in any relation to one another. In it's
-// current state, this introduces some false negatives.
-static bool isCalledByConstructor(const CheckerContext &Context) {
-  const LocationContext *LC = Context.getLocationContext()->getParent();
+static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
+   CheckerContext &Context) {
 
-  while (LC) {
-if (isa(LC->getDecl()))
-  return true;
+  Optional CurrentObject = getObjectVal(Ctor, Context);
+  if (!CurrentObject)
+return false;
+
+  const LocationContext *LC = Context.getLocationContext();
+  while ((LC = LC->getParent())) {
+
+// If \p Ctor was called by another constructor.
+const auto *OtherCtor = dyn_cast(LC->getDecl());
+if (!OtherCtor)
+  continue;
 
-LC = LC->getParent();
+Optional OtherObject =
+getObjectVal(OtherCtor, Context);
+if (!OtherObject)
+  continue;
+
+// If the CurrentObject is a subregion of OtherObject, it will be analyzed
+// during the analysis of OtherObject.
+if (CurrentObject->getRegion()->isSubRegionOf(OtherObject->getRegion()))
+  return true;
   }
+
   return false;
 }
 
Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -1040,13 +1040,12 @@
 // While a singleton would make more sense as a static variable, that would zero
 // initialize all of its fields, hence the not too practical implementation.
 struct Singleton {
-  // TODO: we'd expect the note: {{uninitialized field 'this->i'}}
-  int i; // no-note
+  int i; // expected-note{{uninitialized field 'this->i'}}
+  int dontGetFilteredByNonPedanticMode = 0;
 
   Singleton() {
 assert(!isInstantiated);
-// TODO: we'd expect the warning: {{1 uninitialized field}}
-isInstantiated = true; // no-warning
+isInstantiated = true; // expected-warning{{1 uninitialized field}}
   }
 
   ~Singleton() {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

Thanks! I plan on revisiting how heap allocated regions are handled in the 
future.


https://reviews.llvm.org/D49199



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 159699.
Szelethus added a comment.

Rebased to latest trunk.


https://reviews.llvm.org/D49199

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -196,7 +196,7 @@
 
 struct CyclicPointerTest {
   int *ptr;
-  CyclicPointerTest() : ptr(reinterpret_cast(&ptr)) {}
+  CyclicPointerTest() : ptr(reinterpret_cast(&ptr)) {}
 };
 
 void fCyclicPointerTest() {
@@ -285,13 +285,62 @@
   void *vptr; // no-crash
 
   CyclicVoidPointerTest() : vptr(&vptr) {}
-
 };
 
 void fCyclicVoidPointerTest() {
   CyclicVoidPointerTest();
 }
 
+struct IntDynTypedVoidPointerTest1 {
+  void *vptr; // expected-note{{uninitialized pointee 'this->vptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntDynTypedVoidPointerTest1(void *vptr) : vptr(vptr) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fIntDynTypedVoidPointerTest1() {
+  int a;
+  IntDynTypedVoidPointerTest1 tmp(&a);
+}
+
+struct RecordDynTypedVoidPointerTest {
+  struct RecordType {
+int x; // expected-note{{uninitialized field 'this->vptr->x'}}
+int y; // expected-note{{uninitialized field 'this->vptr->y'}}
+  };
+
+  void *vptr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  RecordDynTypedVoidPointerTest(void *vptr) : vptr(vptr) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fRecordDynTypedVoidPointerTest() {
+  RecordDynTypedVoidPointerTest::RecordType a;
+  RecordDynTypedVoidPointerTest tmp(&a);
+}
+
+struct NestedNonVoidDynTypedVoidPointerTest {
+  struct RecordType {
+int x;  // expected-note{{uninitialized field 'this->vptr->x'}}
+int y;  // expected-note{{uninitialized field 'this->vptr->y'}}
+void *vptr; // expected-note{{uninitialized pointee 'this->vptr->vptr'}}
+  };
+
+  void *vptr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  NestedNonVoidDynTypedVoidPointerTest(void *vptr, void *c) : vptr(vptr) {
+static_cast(vptr)->vptr = c; // expected-warning{{3 uninitialized fields}}
+  }
+};
+
+void fNestedNonVoidDynTypedVoidPointerTest() {
+  NestedNonVoidDynTypedVoidPointerTest::RecordType a;
+  char c;
+  NestedNonVoidDynTypedVoidPointerTest tmp(&a, &c);
+}
+
 //===--===//
 // Multipointer tests.
 //===--===//
Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -776,3 +776,26 @@
 void fVirtualDiamondInheritanceTest3() {
   VirtualDiamondInheritanceTest3();
 }
+
+//===--===//
+// Dynamic type test.
+//===--===//
+
+struct DynTBase {};
+struct DynTDerived : DynTBase {
+  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
+  int x; // no-note
+};
+
+struct DynamicTypeTest {
+  DynTBase *bptr;
+  int i = 0;
+
+  // TODO: we'd expect the warning: {{1 uninitialized field}}
+  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+};
+
+void f() {
+  DynTDerived d;
+  DynamicTypeTest t(&d);
+};
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -44,7 +44,7 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include 
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
 
 using namespace clang;
 using namespace clang::ento;
@@ -236,10 +236,10 @@
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
CheckerContext &Context);
 
-/// Returns whether FD can be (transitively) dereferenced to a void pointer type
+/// Returns whether T can be (transitively) dereferenced to a void pointer type
 /// (void*, void**, ...). The type of the region behind a void pointer isn't
 /// known, and thus FD can not be analyzed.
-static bool isVoidPointer(const FieldDecl *FD);
+static bool isVoidPointer(QualType T);
 
 /// Returns true if T is a primitive type. We defined this type so that for
 /// objects that we'd only like analyze as much as checking whether their
@@ -483,7 +483,7 @@
 
   SVal V = State->getSVal(FR);
 
-  if (V.isUnknown() || V.

[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339240: [analyzer][UninitializedObjectChecker] 
Pointer/reference objects are… (authored by Szelethus, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D49199

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -44,7 +44,7 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include 
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
 
 using namespace clang;
 using namespace clang::ento;
@@ -236,10 +236,10 @@
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
CheckerContext &Context);
 
-/// Returns whether FD can be (transitively) dereferenced to a void pointer type
+/// Returns whether T can be (transitively) dereferenced to a void pointer type
 /// (void*, void**, ...). The type of the region behind a void pointer isn't
 /// known, and thus FD can not be analyzed.
-static bool isVoidPointer(const FieldDecl *FD);
+static bool isVoidPointer(QualType T);
 
 /// Returns true if T is a primitive type. We defined this type so that for
 /// objects that we'd only like analyze as much as checking whether their
@@ -483,7 +483,7 @@
 
   SVal V = State->getSVal(FR);
 
-  if (V.isUnknown() || V.isZeroConstant()) {
+  if (V.isUnknown() || V.getAs()) {
 IsAnyFieldInitialized = true;
 return false;
   }
@@ -497,66 +497,90 @@
 return false;
   }
 
-  const FieldDecl *FD = FR->getDecl();
+  assert(V.getAs() &&
+ "At this point V must be loc::MemRegionVal!");
+  auto L = V.castAs();
+
+  // We can't reason about symbolic regions, assume its initialized.
+  // Note that this also avoids a potential infinite recursion, because
+  // constructors for list-like classes are checked without being called, and
+  // the Static Analyzer will construct a symbolic region for Node *next; or
+  // similar code snippets.
+  if (L.getRegion()->getSymbolicBase()) {
+IsAnyFieldInitialized = true;
+return false;
+  }
 
-  // TODO: The dynamic type of a void pointer may be retrieved with
-  // `getDynamicTypeInfo`.
-  if (isVoidPointer(FD)) {
+  DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
+  if (!DynTInfo.isValid()) {
 IsAnyFieldInitialized = true;
 return false;
   }
 
-  assert(V.getAs() && "V should be Loc at this point!");
+  QualType DynT = DynTInfo.getType();
+
+  if (isVoidPointer(DynT)) {
+IsAnyFieldInitialized = true;
+return false;
+  }
 
   // At this point the pointer itself is initialized and points to a valid
   // location, we'll now check the pointee.
-  SVal DerefdV = State->getSVal(V.castAs());
-
-  // TODO: Dereferencing should be done according to the dynamic type.
-  while (Optional L = DerefdV.getAs()) {
-DerefdV = State->getSVal(*L);
-  }
+  SVal DerefdV = State->getSVal(V.castAs(), DynT);
 
-  // If V is a pointer pointing to a record type.
-  if (Optional RecordV =
-  DerefdV.getAs()) {
+  // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
+  // int** -> int*).
+  while (auto Tmp = DerefdV.getAs()) {
+if (Tmp->getRegion()->getSymbolicBase()) {
+  IsAnyFieldInitialized = true;
+  return false;
+}
 
-const TypedValueRegion *R = RecordV->getRegion();
+DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
+if (!DynTInfo.isValid()) {
+  IsAnyFieldInitialized = true;
+  return false;
+}
 
-// We can't reason about symbolic regions, assume its initialized.
-// Note that this also avoids a potential infinite recursion, because
-// constructors for list-like classes are checked without being called, and
-// the Static Analyzer will construct a symbolic region for Node *next; or
-// similar code snippets.
-if (R->getSymbolicBase()) {
+DynT = DynTInfo.getType();
+if (isVoidPointer(DynT)) {
   IsAnyFieldInitialized = true;
   return false;
 }
 
-const QualType T = R->getValueType();
+DerefdV = State->getSVal(*Tmp, DynT);
+  }
+
+  // If FR is a pointer pointing to a non-primitive type.
+  if (Optional RecordV =
+  DerefdV.getAs()) {
+
+const TypedValueRegion *R = RecordV->getRegion();
 
-if (T->isStructureOrClassType())
+if (DynT->getPointeeType()->isStructureOrClassType())
   return isNonUnionUninit(R, {LocalChain, FR});
 
-if (T->isUnionType()) {
+if (DynT->getPointeeType()->isUnionType()) {
   if (isUnionUn

[PATCH] D49986: [ADT] ImmutableList::add parameters are switched

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a subscriber: dblaikie.
Szelethus added a comment.

In https://reviews.llvm.org/D49985#1181568, @NoQ wrote:

> In https://reviews.llvm.org/D49985#1181564, @dblaikie wrote:
>
> > It looks like concat orders the arguments in the same way that the output 
> > would be (so concat(X, list) produces [X, list]) - so preserving that 
> > argument order seems like it improves/retains readability compared to 
> > switching them around so 'concat(list, X)' produces '[X, list]'.
>
>
> Yeah, i guess that might have been the motivation behind such inconsistency. 
> I'll be fine with fixing the order for other data structures.


@NoQ Have your views changed about this patch? Shall I abandon it?


Repository:
  rC Clang

https://reviews.llvm.org/D49986



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50503: [analyzer][UninitializedObjectChecker] Refactoring p1.: ImmutableList factory is no longer static

2018-08-09 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: NoQ, xazax.hun, rnkovacs, george.karpenkov.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

This diff is the first part of a series of patches to refactor 
`UninitializedObjectChecker`. The goal of this effort is to

- Separate pointer chasing from the rest of the checker,
- Increase readability and reliability,
- Don't impact performance (too bad).

In this patch, `ImmutableList`'s factory is moved to `FindUninitializedFields`.


Repository:
  rC Clang

https://reviews.llvm.org/D50503

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp


Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -73,17 +73,21 @@
 /// Note that this class is immutable, and new fields may only be added through
 /// constructor calls.
 class FieldChainInfo {
+public:
   using FieldChain = llvm::ImmutableList;
 
+private:
+  FieldChain::Factory &Factory;
   FieldChain Chain;
 
   const bool IsDereferenced = false;
 
 public:
-  FieldChainInfo() = default;
+  FieldChainInfo() = delete;
+  FieldChainInfo(FieldChain::Factory &F) : Factory(F) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
-  : Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
+  : Factory(Other.Factory), Chain(Other.Chain), 
IsDereferenced(IsDereferenced) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
  const bool IsDereferenced = false);
@@ -128,6 +132,7 @@
 
   bool IsAnyFieldInitialized = false;
 
+  FieldChainInfo::FieldChain::Factory Factory;
   UninitFieldSet UninitFields;
 
 public:
@@ -217,10 +222,6 @@
 
 } // end of anonymous namespace
 
-// Static variable instantionations.
-
-static llvm::ImmutableListFactory Factory;
-
 // Utility function declarations.
 
 /// Returns the object that was constructed by CtorDecl, or None if that isn't
@@ -355,7 +356,7 @@
   CheckPointeeInitialization(CheckPointeeInitialization) {}
 
 const UninitFieldSet &FindUninitializedFields::getUninitFields() {
-  isNonUnionUninit(ObjectR, FieldChainInfo());
+  isNonUnionUninit(ObjectR, FieldChainInfo(Factory));
 
   if (!IsPedantic && !IsAnyFieldInitialized)
 UninitFields.clear();


Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -73,17 +73,21 @@
 /// Note that this class is immutable, and new fields may only be added through
 /// constructor calls.
 class FieldChainInfo {
+public:
   using FieldChain = llvm::ImmutableList;
 
+private:
+  FieldChain::Factory &Factory;
   FieldChain Chain;
 
   const bool IsDereferenced = false;
 
 public:
-  FieldChainInfo() = default;
+  FieldChainInfo() = delete;
+  FieldChainInfo(FieldChain::Factory &F) : Factory(F) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
-  : Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
+  : Factory(Other.Factory), Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
  const bool IsDereferenced = false);
@@ -128,6 +132,7 @@
 
   bool IsAnyFieldInitialized = false;
 
+  FieldChainInfo::FieldChain::Factory Factory;
   UninitFieldSet UninitFields;
 
 public:
@@ -217,10 +222,6 @@
 
 } // end of anonymous namespace
 
-// Static variable instantionations.
-
-static llvm::ImmutableListFactory Factory;
-
 // Utility function declarations.
 
 /// Returns the object that was constructed by CtorDecl, or None if that isn't
@@ -355,7 +356,7 @@
   CheckPointeeInitialization(CheckPointeeInitialization) {}
 
 const UninitFieldSet &FindUninitializedFields::getUninitFields() {
-  isNonUnionUninit(ObjectR, FieldChainInfo());
+  isNonUnionUninit(ObjectR, FieldChainInfo(Factory));
 
   if (!IsPedantic && !IsAnyFieldInitialized)
 UninitFields.clear();
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50504: [analyzer][UninitializedObjectChecker] Refactoring p2.: Moving pointer chasing to a separate file

2018-08-09 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: george.karpenkov, NoQ, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity, mgorny.

In this patch, the following classes and functions have been moved to a header 
file:

- `FieldChainInfo`
- `FindUninitializedFields`
- `isPrimitiveType`

This also meant that they moved from anonymous namespace to `clang::ento`.

Code related to pointer chasing now relies in its own file.

There's absolutely no functional change in this patch -- its literally just 
copy pasting,


Repository:
  rC Clang

https://reviews.llvm.org/D50504

Files:
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
===
--- /dev/null
+++ lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
@@ -0,0 +1,170 @@
+//===- UninitializedPointer.cpp --*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+//
+// This file defines functions and methods for handling pointers and references
+// to reduce the size and complexity of UninitializedObjectChecker.cpp.
+//
+// To read about command line options and a description what this checker does,
+// refer to UninitializedObjectChecker.cpp.
+//
+// To read about how the checker works, refer to the comments in
+// UninitializedObject.h.
+//
+//===--===//
+
+#include "UninitializedObject.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+
+using namespace clang;
+using namespace clang::ento;
+
+// Utility function declarations.
+
+/// Returns whether T can be (transitively) dereferenced to a void pointer type
+/// (void*, void**, ...). The type of the region behind a void pointer isn't
+/// known, and thus FD can not be analyzed.
+static bool isVoidPointer(QualType T);
+
+//===--===//
+//   Methods for FindUninitializedFields.
+//===--===//
+
+// Note that pointers/references don't contain fields themselves, so in this
+// function we won't add anything to LocalChain.
+bool FindUninitializedFields::isPointerOrReferenceUninit(
+const FieldRegion *FR, FieldChainInfo LocalChain) {
+
+  assert((FR->getDecl()->getType()->isPointerType() ||
+  FR->getDecl()->getType()->isReferenceType()) &&
+ "This method only checks pointer/reference objects!");
+
+  SVal V = State->getSVal(FR);
+
+  if (V.isUnknown() || V.getAs()) {
+IsAnyFieldInitialized = true;
+return false;
+  }
+
+  if (V.isUndef()) {
+return addFieldToUninits({LocalChain, FR});
+  }
+
+  if (!CheckPointeeInitialization) {
+IsAnyFieldInitialized = true;
+return false;
+  }
+
+  assert(V.getAs() &&
+ "At this point V must be loc::MemRegionVal!");
+  auto L = V.castAs();
+
+  // We can't reason about symbolic regions, assume its initialized.
+  // Note that this also avoids a potential infinite recursion, because
+  // constructors for list-like classes are checked without being called, and
+  // the Static Analyzer will construct a symbolic region for Node *next; or
+  // similar code snippets.
+  if (L.getRegion()->getSymbolicBase()) {
+IsAnyFieldInitialized = true;
+return false;
+  }
+
+  DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
+  if (!DynTInfo.isValid()) {
+IsAnyFieldInitialized = true;
+return false;
+  }
+
+  QualType DynT = DynTInfo.getType();
+
+  if (isVoidPointer(DynT)) {
+IsAnyFieldInitialized = true;
+return false;
+  }
+
+  // At this point the pointer itself is initialized and points to a valid
+  // location, we'll now check the pointee.
+  SVal DerefdV = State->getSVal(V.castAs(), DynT);
+
+  // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
+  // int** -> int*).
+  while (auto Tmp = DerefdV.getAs()) {
+if (Tmp->getRegion()->getSymbolicBase()) {
+  IsAnyFieldInitialized = true;
+  return false;
+}
+
+DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
+if (!DynTInfo.isValid()) {
+  IsAnyFieldInitialized = true;
+  return false;
+}
+
+DynT = DynTInfo.getType();
+if (isVoidPointer(DynT)

[PATCH] D50505: [analyzer][UninitializedObjectChecker] Refactoring p3.: printTail moved out from FieldChainInfo

2018-08-09 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: xazax.hun, george.karpenkov, NoQ, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.
Szelethus added a dependency: D50504: [analyzer][UninitializedObjectChecker] 
Refactoring p2.: Moving pointer chasing to a separate file.

This is a standalone part of the effort to reduce `FieldChainInfo`s inteerface.


Repository:
  rC Clang

https://reviews.llvm.org/D50505

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
@@ -18,8 +18,8 @@
 //
 //===--===//
 
-#include "UninitializedObject.h"
 #include "ClangSACheckers.h"
+#include "UninitializedObject.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -40,8 +40,8 @@
 //
 //===--===//
 
-#include "UninitializedObject.h"
 #include "ClangSACheckers.h"
+#include "UninitializedObject.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -81,7 +81,7 @@
 /// (e.g. if the object is a field of another object, in which case we'd check
 /// it multiple times).
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
-   CheckerContext &Context);
+  CheckerContext &Context);
 
 /// Constructs a note message for a given FieldChainInfo object.
 static void printNoteMessage(llvm::raw_ostream &Out,
@@ -305,7 +305,6 @@
   return false;
 }
 
-
 bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) {
   if (V.isUndef())
 return true;
@@ -341,6 +340,13 @@
   return (*Chain.begin())->getDecl();
 }
 
+/// Prints every element except the last to `Out`. Since ImmutableLists store
+/// elements in reverse order, and have no reverse iterators, we use a
+/// recursive function to print the fieldchain correctly. The last element in
+/// the chain is to be printed by `print`.
+static void printTail(llvm::raw_ostream &Out,
+  const FieldChainInfo::FieldChainImpl *L);
+
 // TODO: This function constructs an incorrect string if a void pointer is a
 // part of the chain:
 //
@@ -378,15 +384,13 @@
   if (Chain.isEmpty())
 return;
 
-  const llvm::ImmutableListImpl *L =
-  Chain.getInternalPointer();
+  const FieldChainImpl *L = Chain.getInternalPointer();
   printTail(Out, L->getTail());
   Out << getVariableName(L->getHead()->getDecl());
 }
 
-void FieldChainInfo::printTail(
-llvm::raw_ostream &Out,
-const llvm::ImmutableListImpl *L) {
+static void printTail(llvm::raw_ostream &Out,
+  const FieldChainInfo::FieldChainImpl *L) {
   if (!L)
 return;
 
@@ -415,7 +419,7 @@
 }
 
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
-   CheckerContext &Context) {
+  CheckerContext &Context) {
 
   Optional CurrentObject = getObjectVal(Ctor, Context);
   if (!CurrentObject)
Index: lib/StaticAnalyzer/Checkers/UninitializedObject.h
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject.h
+++ lib/StaticAnalyzer/Checkers/UninitializedObject.h
@@ -35,6 +35,7 @@
 /// constructor calls.
 class FieldChainInfo {
 public:
+  using FieldChainImpl = llvm::ImmutableListImpl;
   using FieldChain = llvm::ImmutableList;
 
 private:
@@ -48,7 +49,8 @@
   FieldChainInfo(FieldChain::Factory &F) : Factory(F) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
-  : Factory(Other.Factory), Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
+  : Factory(Other.Factory), Chain(Other.Chain),
+IsDereferenced(IsDereferenced) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
  const bool IsDereferenced = false);
@@ -64,12 +66,6 @@
   void print(llvm::raw_ostream &Out) const;
 
 private:
-  /// Prints every element except the last to `Out`. Since ImmutableLists store
-  /// elements in reverse order, and have no reverse iterators, we use a
-  /// recur

[PATCH] D50506: [analyzer][UninitializedObjectChecker] Refactoring p4.: Wrap FieldRegions and reduce weight on FieldChainInfo

2018-08-09 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: xazax.hun, rnkovacs, NoQ, george.karpenkov.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

This patch is the bread and butter of the refactoring effort.

Currently on trunk, `FieldChainInfo` is a spaghetti: it takes care of way too 
many cases, even though it was always meant as a wrapper around 
`ImmutableList`.
This problem is solved by introducing a lightweight polymorphic wrapper around 
`const FieldRegion *`, `FieldNode`. It is an interface that abstracts away 
special cases like pointers/references, objects that need to be casted to 
another type for a proper note messages.

I also plan to solve base class related issues with the help on this interface.

Changes to `FieldChainInfo`:

- Now wraps `ImmutableList`.
- Any pointer/reference related fields and methods were removed
- Got a new `add` method. This replaces it's former constructors as a way to 
create a new `FieldChainInfo` objects with a new element.

Changes to `FindUninitializedField`:

- In order not to deal with dynamic memory management, when an uninitialized 
field is found, the note message for it is constructed and is stored instead of 
a `FieldChainInfo` object. (see doc around `addFieldToUninits`).

Some of the test files are changed too, from now on uninitialized pointees of 
references always print "uninitialized pointee" instead of "uninitialized 
field" (which should've really been like this from the beginning).

I also updated every comment according to these changes.


Repository:
  rC Clang

https://reviews.llvm.org/D50506

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -781,7 +781,7 @@
 
 void fLambdaTest2() {
   int b;
-  auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized field 'this->functor.b'}}
+  auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized pointee 'this->functor.b'}}
   LambdaTest2(equals, int());
 }
 #else
@@ -857,8 +857,8 @@
 
 void fMultipleLambdaCapturesTest1() {
   int b1, b2 = 3, b3;
-  auto equals = [&b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b1'}}
-  // expected-note@-1{{uninitialized field 'this->functor.b3'}}
+  auto equals = [&b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized pointee 'this->functor.b1'}}
+  // expected-note@-1{{uninitialized pointee 'this->functor.b3'}}
   MultipleLambdaCapturesTest1(equals, int());
 }
 
@@ -872,7 +872,7 @@
 
 void fMultipleLambdaCapturesTest2() {
   int b1, b2 = 3, b3;
-  auto equals = [b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized field 'this->functor.b3'}}
+  auto equals = [b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized pointee 'this->functor.b3'}}
   MultipleLambdaCapturesTest2(equals, int());
 }
 
Index: lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
@@ -28,6 +28,40 @@
 using namespace clang;
 using namespace clang::ento;
 
+namespace {
+
+/// Represents a pointer or a reference field.
+class LocField : public FieldNode {
+  /// We'll store whether the pointee or the pointer itself is uninitialited.
+  const bool IsDereferenced;
+
+public:
+  LocField(const FieldRegion *FR, const bool IsDereferenced = true)
+  : FieldNode(FR), IsDereferenced(IsDereferenced) {}
+
+  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+if (IsDereferenced)
+  Out << "uninitialized pointee ";
+else
+  Out << "uninitialized pointer ";
+  }
+
+  virtual void printPrefix(llvm::raw_ostream &Out) const override {}
+
+  virtual void printNode(llvm::raw_ostream &Out) const override {
+Out << getVariableName(getDecl());
+  }
+
+  virtual void printSeparator(llvm::raw_ostream &Out) const override {
+if (getDecl()->getType()->isPointerType())
+  Out << "->";
+else
+  Out << '.';
+  }
+};
+
+} // end of anonymous namespace
+
 // Utility function declarations.
 
 /// Returns whether T can be (transitively) dereferenced to a void pointer type
@@ -56,7 +90,8 @@
   }
 
   if (V.isUndef()) {
-return addFieldToUninits({LocalChain, FR});
+return addFieldToUninits(
+LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
   }
 
   if (!CheckPointeeInitialization) {
@@ -125,11 +160,11 @@
 const TypedValueRegion *R = RecordV->getRegion

[PATCH] D50508: [analyzer][UninitializedObjectChecker] Refactoring p5.: Handle pedantic mode in the checker class only

2018-08-09 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: NoQ, george.karpenkov, rnkovacs, xazax.hun.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

A class named `FindUninitializedFields` shouldn't care about whether the 
checker will outright ignore all of its results.


Repository:
  rC Clang

https://reviews.llvm.org/D50508

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp


Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -130,14 +130,20 @@
   if (!Object)
 return;
 
-  FindUninitializedFields F(Context.getState(), Object->getRegion(), 
IsPedantic,
+  FindUninitializedFields F(Context.getState(), Object->getRegion(),
 CheckPointeeInitialization);
 
   const UninitFieldMap &UninitFields = F.getUninitFields();
 
   if (UninitFields.empty())
 return;
 
+  // In non-pedantic mode, if Object's region doesn't contain a single
+  // initialized field, we'll assume that Object was intentionally left
+  // uninitialized.
+  if (!IsPedantic && !F.isAnyFieldInitialized())
+return;
+
   // There are uninitialized fields in the record.
 
   ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState());
@@ -186,18 +192,12 @@
 
//===--===//
 
 FindUninitializedFields::FindUninitializedFields(
-ProgramStateRef State, const TypedValueRegion *const R, bool IsPedantic,
+ProgramStateRef State, const TypedValueRegion *const R,
 bool CheckPointeeInitialization)
-: State(State), ObjectR(R), IsPedantic(IsPedantic),
-  CheckPointeeInitialization(CheckPointeeInitialization) {}
+: State(State), ObjectR(R),
+  CheckPointeeInitialization(CheckPointeeInitialization) {
 
-const UninitFieldMap &FindUninitializedFields::getUninitFields() {
   isNonUnionUninit(ObjectR, FieldChainInfo(ChainFactory));
-
-  if (!IsPedantic && !IsAnyFieldInitialized)
-UninitFields.clear();
-
-  return UninitFields;
 }
 
 bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain) {
Index: lib/StaticAnalyzer/Checkers/UninitializedObject.h
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject.h
+++ lib/StaticAnalyzer/Checkers/UninitializedObject.h
@@ -111,9 +111,7 @@
   ProgramStateRef State;
   const TypedValueRegion *const ObjectR;
 
-  const bool IsPedantic;
   const bool CheckPointeeInitialization;
-
   bool IsAnyFieldInitialized = false;
 
   FieldChainInfo::FieldChain::Factory ChainFactory;
@@ -131,10 +129,17 @@
   UninitFieldMap UninitFields;
 
 public:
+  /// Constructs the FindUninitializedField object, searches for and stores
+  /// uninitialized fields in R.
   FindUninitializedFields(ProgramStateRef State,
-  const TypedValueRegion *const R, bool IsPedantic,
+  const TypedValueRegion *const R,
   bool CheckPointeeInitialization);
-  const UninitFieldMap &getUninitFields();
+
+  const UninitFieldMap &getUninitFields() { return UninitFields; }
+
+  /// Returns whether the analyzed region contains at least one initialized
+  /// field.
+  bool isAnyFieldInitialized() { return IsAnyFieldInitialized; }
 
 private:
   // For the purposes of this checker, we'll regard the object under checking 
as


Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -130,14 +130,20 @@
   if (!Object)
 return;
 
-  FindUninitializedFields F(Context.getState(), Object->getRegion(), IsPedantic,
+  FindUninitializedFields F(Context.getState(), Object->getRegion(),
 CheckPointeeInitialization);
 
   const UninitFieldMap &UninitFields = F.getUninitFields();
 
   if (UninitFields.empty())
 return;
 
+  // In non-pedantic mode, if Object's region doesn't contain a single
+  // initialized field, we'll assume that Object was intentionally left
+  // uninitialized.
+  if (!IsPedantic && !F.isAnyFieldInitialized())
+return;
+
   // There are uninitialized fields in the record.
 
   ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState());
@@ -186,18 +192,12 @@
 //===--===//
 
 FindUninitializedFields::FindUninitializedFields(
-ProgramStateRef State, const TypedValueRegion *const R, bool IsPedantic,
+ProgramStateRef State, const TypedValueRegion *const R,
 bool CheckPointeeInitialization)
-: State(State), ObjectR(R)

[PATCH] D50509: [analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function

2018-08-09 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: george.karpenkov, NoQ, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

Now that it has it's own file, it makes little sense for 
`isPointerOrReferenceUninit` to be this large, so I moved dereferencing to a 
separate function.

Note that this is part 6, but only relies on https://reviews.llvm.org/D50504, 
not part https://reviews.llvm.org/D50508.


Repository:
  rC Clang

https://reviews.llvm.org/D50509

Files:
  lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
@@ -69,6 +69,14 @@
 /// known, and thus FD can not be analyzed.
 static bool isVoidPointer(QualType T);
 
+/// Dereferences V, and stores the dereferences value in it, the dynamic type
+/// of V in DynT, and whether it needs to be casted back in NeedsCastBack.
+///
+/// V must be loc::MemRegionVal.
+///
+/// If for whatever reason dereferencing fails, returns with false.
+static bool dereference(ProgramStateRef State, SVal &V, QualType &DynT);
+
 //===--===//
 //   Methods for FindUninitializedFields.
 //===--===//
@@ -101,61 +109,19 @@
 
   assert(V.getAs() &&
  "At this point V must be loc::MemRegionVal!");
-  auto L = V.castAs();
-
-  // We can't reason about symbolic regions, assume its initialized.
-  // Note that this also avoids a potential infinite recursion, because
-  // constructors for list-like classes are checked without being called, and
-  // the Static Analyzer will construct a symbolic region for Node *next; or
-  // similar code snippets.
-  if (L.getRegion()->getSymbolicBase()) {
-IsAnyFieldInitialized = true;
-return false;
-  }
-
-  DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
-  if (!DynTInfo.isValid()) {
-IsAnyFieldInitialized = true;
-return false;
-  }
-
-  QualType DynT = DynTInfo.getType();
 
-  if (isVoidPointer(DynT)) {
-IsAnyFieldInitialized = true;
-return false;
-  }
+  QualType DynT;
 
   // At this point the pointer itself is initialized and points to a valid
   // location, we'll now check the pointee.
-  SVal DerefdV = State->getSVal(V.castAs(), DynT);
-
-  // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
-  // int** -> int*).
-  while (auto Tmp = DerefdV.getAs()) {
-if (Tmp->getRegion()->getSymbolicBase()) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
-if (!DynTInfo.isValid()) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DynT = DynTInfo.getType();
-if (isVoidPointer(DynT)) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DerefdV = State->getSVal(*Tmp, DynT);
+  if (!dereference(State, V, DynT)) {
+IsAnyFieldInitialized = true;
+return false;
   }
 
   // If FR is a pointer pointing to a non-primitive type.
   if (Optional RecordV =
-  DerefdV.getAs()) {
+  V.getAs()) {
 
 const TypedValueRegion *R = RecordV->getRegion();
 
@@ -184,7 +150,7 @@
  "At this point FR must either have a primitive dynamic type, or it "
  "must be a null, undefined, unknown or concrete pointer!");
 
-  if (isPrimitiveUninit(DerefdV))
+  if (isPrimitiveUninit(V))
 return addFieldToUninits(LocalChain.add(LocField(FR)));
 
   IsAnyFieldInitialized = true;
@@ -203,3 +169,32 @@
   }
   return false;
 }
+
+static bool dereference(ProgramStateRef State, SVal &V, QualType &DynT) {
+  // If V is multiple pointer value, we'll dereference it again (e.g.: int** ->
+  // int*).
+  while (auto Tmp = V.getAs()) {
+// We can't reason about symbolic regions, assume its initialized.
+// Note that this also avoids a potential infinite recursion, because
+// constructors for list-like classes are checked without being called, and
+// the Static Analyzer will construct a symbolic region for Node *next; or
+// similar code snippets.
+if (Tmp->getRegion()->getSymbolicBase()) {
+  return false;
+}
+
+DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
+if (!DynTInfo.isValid()) {
+  return false;
+}
+
+DynT = DynTInfo.getType();
+
+if (isVoidPointer(DynT)) {
+  return false;
+}
+
+V = State->getSVal(*Tmp, DynT);
+  }
+  return true;
+}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50509: [analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function

2018-08-09 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 159916.
Szelethus added a comment.

Fixed a comment.


https://reviews.llvm.org/D50509

Files:
  lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
@@ -69,6 +69,14 @@
 /// known, and thus FD can not be analyzed.
 static bool isVoidPointer(QualType T);
 
+/// Dereferences V, stores the dereferenced value back into it, and stores it's
+/// dynamic type in DynT.
+///
+/// V must be loc::MemRegionVal.
+///
+/// If for whatever reason dereferencing fails, returns with false.
+static bool dereference(ProgramStateRef State, SVal &V, QualType &DynT);
+
 //===--===//
 //   Methods for FindUninitializedFields.
 //===--===//
@@ -101,61 +109,19 @@
 
   assert(V.getAs() &&
  "At this point V must be loc::MemRegionVal!");
-  auto L = V.castAs();
-
-  // We can't reason about symbolic regions, assume its initialized.
-  // Note that this also avoids a potential infinite recursion, because
-  // constructors for list-like classes are checked without being called, and
-  // the Static Analyzer will construct a symbolic region for Node *next; or
-  // similar code snippets.
-  if (L.getRegion()->getSymbolicBase()) {
-IsAnyFieldInitialized = true;
-return false;
-  }
-
-  DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
-  if (!DynTInfo.isValid()) {
-IsAnyFieldInitialized = true;
-return false;
-  }
-
-  QualType DynT = DynTInfo.getType();
 
-  if (isVoidPointer(DynT)) {
-IsAnyFieldInitialized = true;
-return false;
-  }
+  QualType DynT;
 
   // At this point the pointer itself is initialized and points to a valid
   // location, we'll now check the pointee.
-  SVal DerefdV = State->getSVal(V.castAs(), DynT);
-
-  // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
-  // int** -> int*).
-  while (auto Tmp = DerefdV.getAs()) {
-if (Tmp->getRegion()->getSymbolicBase()) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
-if (!DynTInfo.isValid()) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DynT = DynTInfo.getType();
-if (isVoidPointer(DynT)) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DerefdV = State->getSVal(*Tmp, DynT);
+  if (!dereference(State, V, DynT)) {
+IsAnyFieldInitialized = true;
+return false;
   }
 
   // If FR is a pointer pointing to a non-primitive type.
   if (Optional RecordV =
-  DerefdV.getAs()) {
+  V.getAs()) {
 
 const TypedValueRegion *R = RecordV->getRegion();
 
@@ -184,7 +150,7 @@
  "At this point FR must either have a primitive dynamic type, or it "
  "must be a null, undefined, unknown or concrete pointer!");
 
-  if (isPrimitiveUninit(DerefdV))
+  if (isPrimitiveUninit(V))
 return addFieldToUninits(LocalChain.add(LocField(FR)));
 
   IsAnyFieldInitialized = true;
@@ -203,3 +169,32 @@
   }
   return false;
 }
+
+static bool dereference(ProgramStateRef State, SVal &V, QualType &DynT) {
+  // If V is multiple pointer value, we'll dereference it again (e.g.: int** ->
+  // int*).
+  while (auto Tmp = V.getAs()) {
+// We can't reason about symbolic regions, assume its initialized.
+// Note that this also avoids a potential infinite recursion, because
+// constructors for list-like classes are checked without being called, and
+// the Static Analyzer will construct a symbolic region for Node *next; or
+// similar code snippets.
+if (Tmp->getRegion()->getSymbolicBase()) {
+  return false;
+}
+
+DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
+if (!DynTInfo.isValid()) {
+  return false;
+}
+
+DynT = DynTInfo.getType();
+
+if (isVoidPointer(DynT)) {
+  return false;
+}
+
+V = State->getSVal(*Tmp, DynT);
+  }
+  return true;
+}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49228: [analyzer][UninitializedObjectChecker] Void pointer objects are casted back to their dynmic type in note message

2018-08-09 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 159918.
Szelethus added a comment.

The solution now relies on the refactored version of the checker. Note that it 
modifies roughly 75% less code ;).


https://reviews.llvm.org/D49228

Files:
  lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -292,7 +292,7 @@
 }
 
 struct IntDynTypedVoidPointerTest1 {
-  void *vptr; // expected-note{{uninitialized pointee 'this->vptr'}}
+  void *vptr; // expected-note{{uninitialized pointee 'static_cast(this->vptr)'}}
   int dontGetFilteredByNonPedanticMode = 0;
 
   IntDynTypedVoidPointerTest1(void *vptr) : vptr(vptr) {} // expected-warning{{1 uninitialized field}}
@@ -305,8 +305,8 @@
 
 struct RecordDynTypedVoidPointerTest {
   struct RecordType {
-int x; // expected-note{{uninitialized field 'this->vptr->x'}}
-int y; // expected-note{{uninitialized field 'this->vptr->y'}}
+int x; // expected-note{{uninitialized field 'static_cast(this->vptr)->x'}}
+int y; // expected-note{{uninitialized field 'static_cast(this->vptr)->y'}}
   };
 
   void *vptr;
@@ -322,9 +322,9 @@
 
 struct NestedNonVoidDynTypedVoidPointerTest {
   struct RecordType {
-int x;  // expected-note{{uninitialized field 'this->vptr->x'}}
-int y;  // expected-note{{uninitialized field 'this->vptr->y'}}
-void *vptr; // expected-note{{uninitialized pointee 'this->vptr->vptr'}}
+int x;  // expected-note{{uninitialized field 'static_cast(this->vptr)->x'}}
+int y;  // expected-note{{uninitialized field 'static_cast(this->vptr)->y'}}
+void *vptr; // expected-note{{uninitialized pointee 'static_cast(static_cast(this->vptr)->vptr)'}}
   };
 
   void *vptr;
Index: lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedPointee.cpp
@@ -60,6 +60,32 @@
   }
 };
 
+/// Represents a void* field that needs to be casted back to its dynamic type
+/// for a correct note message.
+class NeedsCastLocField : public FieldNode {
+  QualType CastBackType;
+
+public:
+  NeedsCastLocField(const FieldRegion *FR, const QualType &T)
+  : FieldNode(FR), CastBackType(T) {}
+
+  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+Out << "uninitialized pointee ";
+  }
+
+  virtual void printPrefix(llvm::raw_ostream &Out) const override {
+Out << "static_cast" << '<' << CastBackType.getAsString() << ">(";
+  }
+
+  virtual void printNode(llvm::raw_ostream &Out) const {
+Out << getVariableName(getDecl()) << ')';
+  }
+
+  virtual void printSeparator(llvm::raw_ostream &Out) const override {
+Out << "->";
+  }
+};
+
 } // end of anonymous namespace
 
 // Utility function declarations.
@@ -110,6 +136,10 @@
   assert(V.getAs() &&
  "At this point V must be loc::MemRegionVal!");
 
+  // If the static type of the field is a void pointer, we need to cast it back
+  // to the dynamic type before dereferencing.
+  bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
+
   QualType DynT;
 
   // At this point the pointer itself is initialized and points to a valid
@@ -125,11 +155,16 @@
 
 const TypedValueRegion *R = RecordV->getRegion();
 
-if (DynT->getPointeeType()->isStructureOrClassType())
+if (DynT->getPointeeType()->isStructureOrClassType()) {
+  if (NeedsCastBack)
+return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
   return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
+}
 
 if (DynT->getPointeeType()->isUnionType()) {
   if (isUnionUninit(R)) {
+if (NeedsCastBack)
+  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
 return addFieldToUninits(LocalChain.add(LocField(FR)));
   } else {
 IsAnyFieldInitialized = true;
@@ -150,8 +185,11 @@
  "At this point FR must either have a primitive dynamic type, or it "
  "must be a null, undefined, unknown or concrete pointer!");
 
-  if (isPrimitiveUninit(V))
+  if (isPrimitiveUninit(V)) {
+if (NeedsCastBack)
+  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
 return addFieldToUninits(LocalChain.add(LocField(FR)));
+  }
 
   IsAnyFieldInitialized = true;
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50488: [Analyzer] Checker for non-determinism caused by sorting of pointer-like keys

2018-08-10 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp:91-100
+  const QualType IterTy = CE->getArg(0)->getType();
+  const RecordDecl *RD =
+IterTy->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
+
+  if (RD->field_empty())
+return;
+

NoQ wrote:
> This heuristic ("the argument of `std::sort` is //a class whose first field 
> is of pointer type//") is quite wonky, do you have a plan on how to make it 
> more precise?
```
template< class RandomIt >
void sort( RandomIt first, RandomIt last );
```
Since `RandomIt` must satisfy [[ 
https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator | 
RandomAccesIterator ]], maybe you could obtain the value type with 
`std::iterator_traits::value_type`, and check whether it's a pointer type.


Repository:
  rC Clang

https://reviews.llvm.org/D50488



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50488: [Analyzer] Checker for non-determinism caused by sorting of pointer-like keys

2018-08-10 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

I'm only a beginner, but here are some things that caught my eye. I really like 
the idea! :)




Comment at: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp:28
+
+// PointerSortingVisitor class.
+class PointerSortingVisitor : public StmtVisitor {

This comment holds little value.



Comment at: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp:46
+};
+}
+

` // end of anonymous namespace`



Comment at: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp:88
+
+  if (!II->getName().equals("sort"))
+return;

whisperity wrote:
> Brrr... `equals`. StringRef has a `==` and `!=` operator which accepts string 
> literals on the other side, which would result in a more concise code.
> 
> Also, this heuristic can be applied without extra changes (apart from those 
> mentioned by NoQ and might be mentioned later by others) to other sorting 
> functions, such as `std::stable_sort` and `std::stable_partition`. Perhaps it 
> would be worthy to enable checking those functions too.
Maybe `II->isStr("sort")`?



Comment at: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp:93
+  const RecordDecl *RD =
+IterTy->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
+

Is there a reason for not directly acquiring the record declaration?



Comment at: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp:119
+};
+}
+

` // end of anonymous namespace`



Comment at: test/Analysis/ptr-sort.cpp:1
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.nondeterminism.PointerSorting %s -analyzer-output=text 
-verify
+

Always run the core checkers too.
`-analyzer-checker=core,alpha.nondeterminism.PointerSorting`


Repository:
  rC Clang

https://reviews.llvm.org/D50488



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50504: [analyzer][UninitializedObjectChecker] Refactoring p2.: Moving pointer chasing to a separate file

2018-08-13 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 160398.
Szelethus added a comment.

Moved the checker files to `lib/StaticAnalyzer/Checkers/UninitializedObject/`.


https://reviews.llvm.org/D50504

Files:
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ /dev/null
@@ -1,776 +0,0 @@
-//===- UninitializedObjectChecker.cpp *- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===--===//
-//
-// This file defines a checker that reports uninitialized fields in objects
-// created after a constructor call.
-//
-// This checker has several options:
-//   - "Pedantic" (boolean). If its not set or is set to false, the checker
-// won't emit warnings for objects that don't have at least one initialized
-// field. This may be set with
-//
-// `-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true`.
-//
-//   - "NotesAsWarnings" (boolean). If set to true, the checker will emit a
-// warning for each uninitalized field, as opposed to emitting one warning
-// per constructor call, and listing the uninitialized fields that belongs
-// to it in notes. Defaults to false.
-//
-// `-analyzer-config \
-// alpha.cplusplus.UninitializedObject:NotesAsWarnings=true`.
-//
-//   - "CheckPointeeInitialization" (boolean). If set to false, the checker will
-// not analyze the pointee of pointer/reference fields, and will only check
-// whether the object itself is initialized. Defaults to false.
-//
-// `-analyzer-config \
-// alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true`.
-//
-// TODO: With some clever heuristics, some pointers should be dereferenced
-// by default. For example, if the pointee is constructed within the
-// constructor call, it's reasonable to say that no external object
-// references it, and we wouldn't generate multiple report on the same
-// pointee.
-//
-//===--===//
-
-#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
-
-using namespace clang;
-using namespace clang::ento;
-
-namespace {
-
-class UninitializedObjectChecker : public Checker {
-  std::unique_ptr BT_uninitField;
-
-public:
-  // These fields will be initialized when registering the checker.
-  bool IsPedantic;
-  bool ShouldConvertNotesToWarnings;
-  bool CheckPointeeInitialization;
-
-  UninitializedObjectChecker()
-  : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
-  void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
-};
-
-/// Represents a field chain. A field chain is a vector of fields where the
-/// first element of the chain is the object under checking (not stored), and
-/// every other element is a field, and the element that precedes it is the
-/// object that contains it.
-///
-/// Note that this class is immutable, and new fields may only be added through
-/// constructor calls.
-class FieldChainInfo {
-public:
-  using FieldChain = llvm::ImmutableList;
-
-private:
-  FieldChain::Factory &Factory;
-  FieldChain Chain;
-
-  const bool IsDereferenced = false;
-
-public:
-  FieldChainInfo() = delete;
-  FieldChainInfo(FieldChain::Factory &F) : Factory(F) {}
-
-  FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
-  : Factory(Other.Factory), Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
-
-  FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
- const bool IsDereferenced = false);
-
-  bool contains(const FieldRegion *FR) const { return Chain.contains(FR); }
-  bool isPointer() const;
-
-  /// If this is a fieldchain whose last element is an uninitialized region of a
-  /// pointer type, `IsDereferenced` will store whether the pointer itself or
-  /// the pointee is uninitialized.
-  bool isDereferenced() const;
-  const FieldDecl *getEndOfChain() const;
-  void print(llvm::raw_ostream &Out) const;
-
-private:
-  /// Prints every element except the last to `Out`. Since ImmutableLists store
-  /// elements in reverse order, and have n

[PATCH] D50503: [analyzer][UninitializedObjectChecker] Refactoring p1.: ImmutableList factory is no longer static

2018-08-13 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL339591: [analyzer][UninitializedObjectChecker] Refactoring 
p1.: ImmutableList factory… (authored by Szelethus, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D50503?vs=159889&id=160400#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D50503

Files:
  cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp


Index: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -73,17 +73,21 @@
 /// Note that this class is immutable, and new fields may only be added through
 /// constructor calls.
 class FieldChainInfo {
+public:
   using FieldChain = llvm::ImmutableList;
 
+private:
+  FieldChain::Factory &Factory;
   FieldChain Chain;
 
   const bool IsDereferenced = false;
 
 public:
-  FieldChainInfo() = default;
+  FieldChainInfo() = delete;
+  FieldChainInfo(FieldChain::Factory &F) : Factory(F) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
-  : Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
+  : Factory(Other.Factory), Chain(Other.Chain), 
IsDereferenced(IsDereferenced) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
  const bool IsDereferenced = false);
@@ -128,6 +132,7 @@
 
   bool IsAnyFieldInitialized = false;
 
+  FieldChainInfo::FieldChain::Factory Factory;
   UninitFieldSet UninitFields;
 
 public:
@@ -217,10 +222,6 @@
 
 } // end of anonymous namespace
 
-// Static variable instantionations.
-
-static llvm::ImmutableListFactory Factory;
-
 // Utility function declarations.
 
 /// Returns the object that was constructed by CtorDecl, or None if that isn't
@@ -355,7 +356,7 @@
   CheckPointeeInitialization(CheckPointeeInitialization) {}
 
 const UninitFieldSet &FindUninitializedFields::getUninitFields() {
-  isNonUnionUninit(ObjectR, FieldChainInfo());
+  isNonUnionUninit(ObjectR, FieldChainInfo(Factory));
 
   if (!IsPedantic && !IsAnyFieldInitialized)
 UninitFields.clear();


Index: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -73,17 +73,21 @@
 /// Note that this class is immutable, and new fields may only be added through
 /// constructor calls.
 class FieldChainInfo {
+public:
   using FieldChain = llvm::ImmutableList;
 
+private:
+  FieldChain::Factory &Factory;
   FieldChain Chain;
 
   const bool IsDereferenced = false;
 
 public:
-  FieldChainInfo() = default;
+  FieldChainInfo() = delete;
+  FieldChainInfo(FieldChain::Factory &F) : Factory(F) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
-  : Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
+  : Factory(Other.Factory), Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
  const bool IsDereferenced = false);
@@ -128,6 +132,7 @@
 
   bool IsAnyFieldInitialized = false;
 
+  FieldChainInfo::FieldChain::Factory Factory;
   UninitFieldSet UninitFields;
 
 public:
@@ -217,10 +222,6 @@
 
 } // end of anonymous namespace
 
-// Static variable instantionations.
-
-static llvm::ImmutableListFactory Factory;
-
 // Utility function declarations.
 
 /// Returns the object that was constructed by CtorDecl, or None if that isn't
@@ -355,7 +356,7 @@
   CheckPointeeInitialization(CheckPointeeInitialization) {}
 
 const UninitFieldSet &FindUninitializedFields::getUninitFields() {
-  isNonUnionUninit(ObjectR, FieldChainInfo());
+  isNonUnionUninit(ObjectR, FieldChainInfo(Factory));
 
   if (!IsPedantic && !IsAnyFieldInitialized)
 UninitFields.clear();
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50504: [analyzer][UninitializedObjectChecker] Refactoring p2.: Moving pointer chasing to a separate file

2018-08-13 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339595: [analyzer][UninitializedObjectChecker] Refactoring 
p2.: Moving pointer chasing… (authored by Szelethus, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D50504

Files:
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -0,0 +1,487 @@
+//===- UninitializedObjectChecker.cpp *- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+//
+// This file defines a checker that reports uninitialized fields in objects
+// created after a constructor call.
+//
+// This checker has several options:
+//   - "Pedantic" (boolean). If its not set or is set to false, the checker
+// won't emit warnings for objects that don't have at least one initialized
+// field. This may be set with
+//
+// `-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true`.
+//
+//   - "NotesAsWarnings" (boolean). If set to true, the checker will emit a
+// warning for each uninitalized field, as opposed to emitting one warning
+// per constructor call, and listing the uninitialized fields that belongs
+// to it in notes. Defaults to false.
+//
+// `-analyzer-config \
+// alpha.cplusplus.UninitializedObject:NotesAsWarnings=true`.
+//
+//   - "CheckPointeeInitialization" (boolean). If set to false, the checker will
+// not analyze the pointee of pointer/reference fields, and will only check
+// whether the object itself is initialized. Defaults to false.
+//
+// `-analyzer-config \
+// alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true`.
+//
+// TODO: With some clever heuristics, some pointers should be dereferenced
+// by default. For example, if the pointee is constructed within the
+// constructor call, it's reasonable to say that no external object
+// references it, and we wouldn't generate multiple report on the same
+// pointee.
+//
+// To read about how the checker works, refer to the comments in
+// UninitializedObject.h.
+//
+// Some of the logic is implemented in UninitializedPointee.cpp, to reduce the
+// complexity of this file.
+//
+//===--===//
+
+#include "UninitializedObject.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+
+using namespace clang;
+using namespace clang::ento;
+
+namespace {
+
+class UninitializedObjectChecker : public Checker {
+  std::unique_ptr BT_uninitField;
+
+public:
+  // These fields will be initialized when registering the checker.
+  bool IsPedantic;
+  bool ShouldConvertNotesToWarnings;
+  bool CheckPointeeInitialization;
+
+  UninitializedObjectChecker()
+  : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
+  void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
+};
+
+} // end of anonymous namespace
+
+// Utility function declarations.
+
+/// Returns the object that was constructed by CtorDecl, or None if that isn't
+/// possible.
+// TODO: Refactor this function so that it returns the constructed object's
+// region.
+static Optional
+getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
+
+/// Checks whether the object constructed by \p Ctor will be analyzed later
+/// (e.g. if the object is a field of another object, in which case we'd check
+/// it multiple times).
+static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
+   CheckerContext &Context);
+
+/// Constructs a note message for a given FieldChainInfo object.
+static void printNoteMessage(llvm::raw_ostream &Out,
+ const FieldChainInfo &Chain);
+
+/// Returns with Field's name. This is a helper function to get the correct name
+/// even if Field is a captured lambda variable.
+static StringRef getVariableName(const FieldDecl *Field);
+
+//===--

[PATCH] D50505: [analyzer][UninitializedObjectChecker] Refactoring p3.: printTail moved out from FieldChainInfo

2018-08-13 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339596: [analyzer][UninitializedObjectChecker] Refactoring 
p3.: printTail moved out… (authored by Szelethus, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D50505?vs=159891&id=160406#toc

Repository:
  rC Clang

https://reviews.llvm.org/D50505

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -18,8 +18,8 @@
 //
 //===--===//
 
-#include "UninitializedObject.h"
 #include "ClangSACheckers.h"
+#include "UninitializedObject.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -46,8 +46,8 @@
 //
 //===--===//
 
-#include "UninitializedObject.h"
 #include "ClangSACheckers.h"
+#include "UninitializedObject.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -87,7 +87,7 @@
 /// (e.g. if the object is a field of another object, in which case we'd check
 /// it multiple times).
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
-   CheckerContext &Context);
+  CheckerContext &Context);
 
 /// Constructs a note message for a given FieldChainInfo object.
 static void printNoteMessage(llvm::raw_ostream &Out,
@@ -346,6 +346,13 @@
   return (*Chain.begin())->getDecl();
 }
 
+/// Prints every element except the last to `Out`. Since ImmutableLists store
+/// elements in reverse order, and have no reverse iterators, we use a
+/// recursive function to print the fieldchain correctly. The last element in
+/// the chain is to be printed by `print`.
+static void printTail(llvm::raw_ostream &Out,
+  const FieldChainInfo::FieldChainImpl *L);
+
 // TODO: This function constructs an incorrect string if a void pointer is a
 // part of the chain:
 //
@@ -383,15 +390,13 @@
   if (Chain.isEmpty())
 return;
 
-  const llvm::ImmutableListImpl *L =
-  Chain.getInternalPointer();
+  const FieldChainImpl *L = Chain.getInternalPointer();
   printTail(Out, L->getTail());
   Out << getVariableName(L->getHead()->getDecl());
 }
 
-void FieldChainInfo::printTail(
-llvm::raw_ostream &Out,
-const llvm::ImmutableListImpl *L) {
+static void printTail(llvm::raw_ostream &Out,
+  const FieldChainInfo::FieldChainImpl *L) {
   if (!L)
 return;
 
@@ -420,7 +425,7 @@
 }
 
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
-   CheckerContext &Context) {
+  CheckerContext &Context) {
 
   Optional CurrentObject = getObjectVal(Ctor, Context);
   if (!CurrentObject)
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
@@ -35,6 +35,7 @@
 /// constructor calls.
 class FieldChainInfo {
 public:
+  using FieldChainImpl = llvm::ImmutableListImpl;
   using FieldChain = llvm::ImmutableList;
 
 private:
@@ -48,7 +49,8 @@
   FieldChainInfo(FieldChain::Factory &F) : Factory(F) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
-  : Factory(Other.Factory), Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
+  : Factory(Other.Factory), Chain(Other.Chain),
+IsDereferenced(IsDereferenced) {}
 
   FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
  const bool IsDereferenced = false);
@@ -64,12 +66,6 @@
   void print(llvm::raw_ostream &Out) const;
 
 private:
-  /// Prints every element except the last to `Out`. Since ImmutableLists store
-  /// elements in reverse order, and have no reverse iterators, we use a
-  /// recursive function to 

[PATCH] D50506: [analyzer][UninitializedObjectChecker] Refactoring p4.: Wrap FieldRegions and reduce weight on FieldChainInfo

2018-08-13 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339599: [analyzer][UninitializedObjectChecker] Refactoring 
p4.: Wrap FieldRegions and… (authored by Szelethus, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D50506?vs=159896&id=160417#toc

Repository:
  rC Clang

https://reviews.llvm.org/D50506

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object.cpp
  test/Analysis/objcpp-uninitialized-object.mm

Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -72,6 +72,27 @@
   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
 };
 
+/// A basic field type, that is not a pointer or a reference, it's dynamic and
+/// static type is the same.
+class RegularField : public FieldNode {
+public:
+  RegularField(const FieldRegion *FR) : FieldNode(FR) {}
+
+  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+Out << "uninitialized field ";
+  }
+
+  virtual void printPrefix(llvm::raw_ostream &Out) const override {}
+
+  virtual void printNode(llvm::raw_ostream &Out) const {
+Out << getVariableName(getDecl());
+  }
+
+  virtual void printSeparator(llvm::raw_ostream &Out) const override {
+Out << '.';
+  }
+};
+
 } // end of anonymous namespace
 
 // Utility function declarations.
@@ -89,14 +110,6 @@
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
   CheckerContext &Context);
 
-/// Constructs a note message for a given FieldChainInfo object.
-static void printNoteMessage(llvm::raw_ostream &Out,
- const FieldChainInfo &Chain);
-
-/// Returns with Field's name. This is a helper function to get the correct name
-/// even if Field is a captured lambda variable.
-static StringRef getVariableName(const FieldDecl *Field);
-
 //===--===//
 //  Methods for UninitializedObjectChecker.
 //===--===//
@@ -126,7 +139,7 @@
   FindUninitializedFields F(Context.getState(), Object->getRegion(), IsPedantic,
 CheckPointeeInitialization);
 
-  const UninitFieldSet &UninitFields = F.getUninitFields();
+  const UninitFieldMap &UninitFields = F.getUninitFields();
 
   if (UninitFields.empty())
 return;
@@ -146,14 +159,10 @@
   // For Plist consumers that don't support notes just yet, we'll convert notes
   // to warnings.
   if (ShouldConvertNotesToWarnings) {
-for (const auto &Chain : UninitFields) {
-  SmallString<100> WarningBuf;
-  llvm::raw_svector_ostream WarningOS(WarningBuf);
-
-  printNoteMessage(WarningOS, Chain);
+for (const auto &Pair : UninitFields) {
 
   auto Report = llvm::make_unique(
-  *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
+  *BT_uninitField, Pair.second, Node, LocUsedForUniqueing,
   Node->getLocationContext()->getDecl());
   Context.emitReport(std::move(Report));
 }
@@ -170,14 +179,9 @@
   *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
   Node->getLocationContext()->getDecl());
 
-  for (const auto &Chain : UninitFields) {
-SmallString<200> NoteBuf;
-llvm::raw_svector_ostream NoteOS(NoteBuf);
-
-printNoteMessage(NoteOS, Chain);
-
-Report->addNote(NoteOS.str(),
-PathDiagnosticLocation::create(Chain.getEndOfChain(),
+  for (const auto &Pair : UninitFields) {
+Report->addNote(Pair.second,
+PathDiagnosticLocation::create(Pair.first->getDecl(),
Context.getSourceManager()));
   }
   Context.emitReport(std::move(Report));
@@ -193,8 +197,8 @@
 : State(State), ObjectR(R), IsPedantic(IsPedantic),
   CheckPointeeInitialization(CheckPointeeInitialization) {}
 
-const UninitFieldSet &FindUninitializedFields::getUninitFields() {
-  isNonUnionUninit(ObjectR, FieldChainInfo(Factory));
+const UninitFieldMap &FindUninitializedFields::getUninitFields() {
+  isNonUnionUninit(ObjectR, FieldChainInfo(ChainFactory));
 
   if (!IsPedantic && !IsAnyFieldInitialized)
 UninitFields.clear();
@@ -204,10 +208,15 @@
 
 bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain) {
   if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
-  Chain.getEndOfChain()->getLocation()))
+  Chain.getUninitRegion()->getDecl()->getLocati

[PATCH] D50508: [analyzer][UninitializedObjectChecker] Refactoring p5.: Handle pedantic mode in the checker class only

2018-08-13 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339601: [analyzer][UninitializedObjectChecker] Refactoring 
p5.: Handle pedantic mode in… (authored by Szelethus, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D50508?vs=159901&id=160420#toc

Repository:
  rC Clang

https://reviews.llvm.org/D50508

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp


Index: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -136,14 +136,20 @@
   if (!Object)
 return;
 
-  FindUninitializedFields F(Context.getState(), Object->getRegion(), 
IsPedantic,
+  FindUninitializedFields F(Context.getState(), Object->getRegion(),
 CheckPointeeInitialization);
 
   const UninitFieldMap &UninitFields = F.getUninitFields();
 
   if (UninitFields.empty())
 return;
 
+  // In non-pedantic mode, if Object's region doesn't contain a single
+  // initialized field, we'll assume that Object was intentionally left
+  // uninitialized.
+  if (!IsPedantic && !F.isAnyFieldInitialized())
+return;
+
   // There are uninitialized fields in the record.
 
   ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState());
@@ -192,18 +198,12 @@
 
//===--===//
 
 FindUninitializedFields::FindUninitializedFields(
-ProgramStateRef State, const TypedValueRegion *const R, bool IsPedantic,
+ProgramStateRef State, const TypedValueRegion *const R,
 bool CheckPointeeInitialization)
-: State(State), ObjectR(R), IsPedantic(IsPedantic),
-  CheckPointeeInitialization(CheckPointeeInitialization) {}
+: State(State), ObjectR(R),
+  CheckPointeeInitialization(CheckPointeeInitialization) {
 
-const UninitFieldMap &FindUninitializedFields::getUninitFields() {
   isNonUnionUninit(ObjectR, FieldChainInfo(ChainFactory));
-
-  if (!IsPedantic && !IsAnyFieldInitialized)
-UninitFields.clear();
-
-  return UninitFields;
 }
 
 bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain) {
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
@@ -111,9 +111,7 @@
   ProgramStateRef State;
   const TypedValueRegion *const ObjectR;
 
-  const bool IsPedantic;
   const bool CheckPointeeInitialization;
-
   bool IsAnyFieldInitialized = false;
 
   FieldChainInfo::FieldChain::Factory ChainFactory;
@@ -131,10 +129,17 @@
   UninitFieldMap UninitFields;
 
 public:
+  /// Constructs the FindUninitializedField object, searches for and stores
+  /// uninitialized fields in R.
   FindUninitializedFields(ProgramStateRef State,
-  const TypedValueRegion *const R, bool IsPedantic,
+  const TypedValueRegion *const R,
   bool CheckPointeeInitialization);
-  const UninitFieldMap &getUninitFields();
+
+  const UninitFieldMap &getUninitFields() { return UninitFields; }
+
+  /// Returns whether the analyzed region contains at least one initialized
+  /// field.
+  bool isAnyFieldInitialized() { return IsAnyFieldInitialized; }
 
 private:
   // For the purposes of this checker, we'll regard the object under checking 
as


Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -136,14 +136,20 @@
   if (!Object)
 return;
 
-  FindUninitializedFields F(Context.getState(), Object->getRegion(), IsPedantic,
+  FindUninitializedFields F(Context.getState(), Object->getRegion(),
 CheckPointeeInitialization);
 
   const UninitFieldMap &UninitFields = F.getUninitFields();
 
   if (UninitFields.empty())
 return;
 
+  // In non-pedantic mode, if Object's region doesn't contain a single
+  // initialized field, we'll assume that Object was intentionally left
+  // uninitialized.
+  if (!IsPedantic && !F.isAnyFieldInitialized())
+return;
+
   // There are uninitialized fields in the record.
 
   ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState());
@@ -192,18 +198,12 @@
 //===--===//
 
 FindUninitializedFields::FindUninitializedFie

[PATCH] D49228: [analyzer][UninitializedObjectChecker] Void pointer objects are casted back to their dynmic type in note message

2018-08-14 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339653: [analyzer][UninitializedObjectChecker] Void pointers 
are casted back to their… (authored by Szelethus, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D49228?vs=159918&id=160526#toc

Repository:
  rC Clang

https://reviews.llvm.org/D49228

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -292,7 +292,7 @@
 }
 
 struct IntDynTypedVoidPointerTest1 {
-  void *vptr; // expected-note{{uninitialized pointee 'this->vptr'}}
+  void *vptr; // expected-note{{uninitialized pointee 'static_cast(this->vptr)'}}
   int dontGetFilteredByNonPedanticMode = 0;
 
   IntDynTypedVoidPointerTest1(void *vptr) : vptr(vptr) {} // expected-warning{{1 uninitialized field}}
@@ -305,8 +305,8 @@
 
 struct RecordDynTypedVoidPointerTest {
   struct RecordType {
-int x; // expected-note{{uninitialized field 'this->vptr->x'}}
-int y; // expected-note{{uninitialized field 'this->vptr->y'}}
+int x; // expected-note{{uninitialized field 'static_cast(this->vptr)->x'}}
+int y; // expected-note{{uninitialized field 'static_cast(this->vptr)->y'}}
   };
 
   void *vptr;
@@ -322,9 +322,9 @@
 
 struct NestedNonVoidDynTypedVoidPointerTest {
   struct RecordType {
-int x;  // expected-note{{uninitialized field 'this->vptr->x'}}
-int y;  // expected-note{{uninitialized field 'this->vptr->y'}}
-void *vptr; // expected-note{{uninitialized pointee 'this->vptr->vptr'}}
+int x;  // expected-note{{uninitialized field 'static_cast(this->vptr)->x'}}
+int y;  // expected-note{{uninitialized field 'static_cast(this->vptr)->y'}}
+void *vptr; // expected-note{{uninitialized pointee 'static_cast(static_cast(this->vptr)->vptr)'}}
   };
 
   void *vptr;
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -60,6 +60,32 @@
   }
 };
 
+/// Represents a void* field that needs to be casted back to its dynamic type
+/// for a correct note message.
+class NeedsCastLocField final : public FieldNode {
+  QualType CastBackType;
+
+public:
+  NeedsCastLocField(const FieldRegion *FR, const QualType &T)
+  : FieldNode(FR), CastBackType(T) {}
+
+  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+Out << "uninitialized pointee ";
+  }
+
+  virtual void printPrefix(llvm::raw_ostream &Out) const override {
+Out << "static_cast" << '<' << CastBackType.getAsString() << ">(";
+  }
+
+  virtual void printNode(llvm::raw_ostream &Out) const override {
+Out << getVariableName(getDecl()) << ')';
+  }
+
+  virtual void printSeparator(llvm::raw_ostream &Out) const override {
+Out << "->";
+  }
+};
+
 } // end of anonymous namespace
 
 // Utility function declarations.
@@ -122,6 +148,10 @@
 
   QualType DynT = DynTInfo.getType();
 
+  // If the static type of the field is a void pointer, we need to cast it back
+  // to the dynamic type before dereferencing.
+  bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
+
   if (isVoidPointer(DynT)) {
 IsAnyFieldInitialized = true;
 return false;
@@ -160,11 +190,16 @@
 
 const TypedValueRegion *R = RecordV->getRegion();
 
-if (DynT->getPointeeType()->isStructureOrClassType())
+if (DynT->getPointeeType()->isStructureOrClassType()) {
+  if (NeedsCastBack)
+return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
   return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
+}
 
 if (DynT->getPointeeType()->isUnionType()) {
   if (isUnionUninit(R)) {
+if (NeedsCastBack)
+  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
 return addFieldToUninits(LocalChain.add(LocField(FR)));
   } else {
 IsAnyFieldInitialized = true;
@@ -185,8 +220,11 @@
  "At this point FR must either have a primitive dynamic type, or it "
  "must be a null, undefined, unknown or concrete pointer!");
 
-  if (isPrimitiveUninit(DerefdV))
+  if (isPrimitiveUninit(DerefdV)) {
+if (NeedsCastBack)
+  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
 return addFieldToUninits(LocalChain.add(LocField(FR)));
+  }
 
   IsAnyFieldInitialized = true;
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46081: [analyzer] Expand conversion check to check more expressions for overflow and underflow

2018-08-15 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.
Herald added a subscriber: mikhail.ramalho.

To me it seems like @pfultz2 hasn't been on the site for a couple months. Is 
this patch going to be commited anytime?


https://reviews.llvm.org/D46081



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50488: [Analyzer] Checker for non-determinism caused by sorting of pointer-like keys

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

I think testcases for non-class iterator objects would be valuable.




Comment at: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp:72-76
+  auto IteratesPointerKeysM = hasType(cxxRecordDecl(has(
+fieldDecl(hasType(hasCanonicalType(
+  pointsTo(hasCanonicalType(pointerType()))
+)))
+  )));

I'm not a matcher-expert, but here we go:

As I understand it, you're matching iterator objects that wrap a pointer to 
pointer. Would it match this case?:

```
void fill(int **IntPointerArray);

int main() {
  int *IntPointerArray[20]; // or a simple int array
  fill(IntPointerArray);

  std::sort(IntPointerArray, IntPointerArray + 20);
}
```
`int**` is an [[ 
https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator | 
RandomAccessIterator ]], but is not a `CXXRecordDecl`. As I mentioned earlier, 
it might be worth taking a look at `hasType`, and attempt to acquire 
`value_type`, as it is required for STL algorithms (it could be in a base class 
as well). `value_type` is also predefined through `std::iterator_traits` for 
pointer iterators like `int**`.


https://reviews.llvm.org/D50488



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50509: [analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 161209.
Szelethus edited the summary of this revision.

https://reviews.llvm.org/D50509

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -95,6 +95,12 @@
 /// known, and thus FD can not be analyzed.
 static bool isVoidPointer(QualType T);
 
+/// Dereferences \p V and returns the value and dynamic type of the pointee, as
+/// well as wether \p FR needs to be casted back to that type. If for whatever
+/// reason dereferencing fails, returns with None.
+static llvm::Optional>
+dereference(ProgramStateRef State, const FieldRegion *FR);
+
 //===--===//
 //   Methods for FindUninitializedFields.
 //===--===//
@@ -126,67 +132,21 @@
 return false;
   }
 
-  assert(V.getAs() &&
- "At this point V must be loc::MemRegionVal!");
-  auto L = V.castAs();
-
-  // We can't reason about symbolic regions, assume its initialized.
-  // Note that this also avoids a potential infinite recursion, because
-  // constructors for list-like classes are checked without being called, and
-  // the Static Analyzer will construct a symbolic region for Node *next; or
-  // similar code snippets.
-  if (L.getRegion()->getSymbolicBase()) {
-IsAnyFieldInitialized = true;
-return false;
-  }
-
-  DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
-  if (!DynTInfo.isValid()) {
-IsAnyFieldInitialized = true;
-return false;
-  }
-
-  QualType DynT = DynTInfo.getType();
-
-  // If the static type of the field is a void pointer, we need to cast it back
-  // to the dynamic type before dereferencing.
-  bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
-
-  if (isVoidPointer(DynT)) {
+  // At this point the pointer itself is initialized and points to a valid
+  // location, we'll now check the pointee.
+  llvm::Optional> DerefInfo = dereference(State, FR);
+  if (!DerefInfo) {
 IsAnyFieldInitialized = true;
 return false;
   }
 
-  // At this point the pointer itself is initialized and points to a valid
-  // location, we'll now check the pointee.
-  SVal DerefdV = State->getSVal(V.castAs(), DynT);
-
-  // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
-  // int** -> int*).
-  while (auto Tmp = DerefdV.getAs()) {
-if (Tmp->getRegion()->getSymbolicBase()) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
-if (!DynTInfo.isValid()) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DynT = DynTInfo.getType();
-if (isVoidPointer(DynT)) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DerefdV = State->getSVal(*Tmp, DynT);
-  }
+  V = std::get<0>(*DerefInfo);
+  QualType DynT = std::get<1>(*DerefInfo);
+  bool NeedsCastBack = std::get<2>(*DerefInfo);
 
   // If FR is a pointer pointing to a non-primitive type.
   if (Optional RecordV =
-  DerefdV.getAs()) {
+  V.getAs()) {
 
 const TypedValueRegion *R = RecordV->getRegion();
 
@@ -222,7 +182,7 @@
  "must be a null, undefined, unknown or concrete pointer!");
   (void)IsPrimitive;
 
-  if (isPrimitiveUninit(DerefdV)) {
+  if (isPrimitiveUninit(V)) {
 if (NeedsCastBack)
   return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
 return addFieldToUninits(LocalChain.add(LocField(FR)));
@@ -244,3 +204,45 @@
   }
   return false;
 }
+
+static llvm::Optional>
+dereference(ProgramStateRef State, const FieldRegion *FR) {
+
+  DynamicTypeInfo DynTInfo;
+  QualType DynT;
+
+  // If the static type of the field is a void pointer, we need to cast it back
+  // to the dynamic type before dereferencing.
+  bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
+
+  SVal V = State->getSVal(FR);
+  assert(V.getAs() && "V must be loc::MemRegionVal!");
+
+  // If V is multiple pointer value, we'll dereference it again (e.g.: int** ->
+  // int*).
+  while (auto Tmp = V.getAs()) {
+// We can't reason about symbolic regions, assume its initialized.
+// Note that this also avoids a potential infinite recursion, because
+// constructors for list-like classes are checked without being called, and
+// the Static Analyzer will construct a symbolic region for Node *next; or
+// similar code snippets.
+if (Tmp->getRegion()->getSymbolicBase()) {
+  return None;
+}
+
+DynTInfo = getDynamicTypeInfo(State, Tmp->ge

[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: george.karpenkov, NoQ, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

Repository:
  rC Clang

https://reviews.llvm.org/D50892

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp


Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -781,21 +781,40 @@
 // Dynamic type test.
 
//===--===//
 
-struct DynTBase {};
-struct DynTDerived : DynTBase {
+struct DynTBase1 {};
+struct DynTDerived1 : DynTBase1 {
   // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
   int x; // no-note
 };
 
-struct DynamicTypeTest {
-  DynTBase *bptr;
+struct DynamicTypeTest1 {
+  DynTBase1 *bptr;
   int i = 0;
 
   // TODO: we'd expect the warning: {{1 uninitialized field}}
-  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+  DynamicTypeTest1(DynTBase1 *bptr) : bptr(bptr) {} // no-warning
 };
 
-void f() {
-  DynTDerived d;
-  DynamicTypeTest t(&d);
+void fDynamicTypeTest1() {
+  DynTDerived1 d;
+  DynamicTypeTest1 t(&d);
 };
+
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'this->bptr->x'}}
+};
+struct DynTDerived2 : DynTBase2 {
+  int y; // expected-note{{uninitialized field 'this->bptr->y'}}
+};
+
+struct DynamicTypeTest2 {
+  DynTBase2 *bptr;
+  int i = 0;
+
+  DynamicTypeTest2(DynTBase2 *bptr) : bptr(bptr) {} // expected-warning{{2 
uninitialized fields}}
+};
+
+void fDynamicTypeTest2() {
+  DynTDerived2 d;
+  DynamicTypeTest2 t(&d);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -190,6 +190,10 @@
 
 const TypedValueRegion *R = RecordV->getRegion();
 
+while (R->getAs()) {
+  R = R->getSuperRegion()->getAs();
+}
+
 if (DynT->getPointeeType()->isStructureOrClassType()) {
   if (NeedsCastBack)
 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, 
DynT)));


Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -781,21 +781,40 @@
 // Dynamic type test.
 //===--===//
 
-struct DynTBase {};
-struct DynTDerived : DynTBase {
+struct DynTBase1 {};
+struct DynTDerived1 : DynTBase1 {
   // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
   int x; // no-note
 };
 
-struct DynamicTypeTest {
-  DynTBase *bptr;
+struct DynamicTypeTest1 {
+  DynTBase1 *bptr;
   int i = 0;
 
   // TODO: we'd expect the warning: {{1 uninitialized field}}
-  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+  DynamicTypeTest1(DynTBase1 *bptr) : bptr(bptr) {} // no-warning
 };
 
-void f() {
-  DynTDerived d;
-  DynamicTypeTest t(&d);
+void fDynamicTypeTest1() {
+  DynTDerived1 d;
+  DynamicTypeTest1 t(&d);
 };
+
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'this->bptr->x'}}
+};
+struct DynTDerived2 : DynTBase2 {
+  int y; // expected-note{{uninitialized field 'this->bptr->y'}}
+};
+
+struct DynamicTypeTest2 {
+  DynTBase2 *bptr;
+  int i = 0;
+
+  DynamicTypeTest2(DynTBase2 *bptr) : bptr(bptr) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fDynamicTypeTest2() {
+  DynTDerived2 d;
+  DynamicTypeTest2 t(&d);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -190,6 +190,10 @@
 
 const TypedValueRegion *R = RecordV->getRegion();
 
+while (R->getAs()) {
+  R = R->getSuperRegion()->getAs();
+}
+
 if (DynT->getPointeeType()->isStructureOrClassType()) {
   if (NeedsCastBack)
 return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: test/Analysis/cxx-uninitialized-object-inheritance.cpp:787
   // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
   int x; // no-note
 };

The checker should be able to catch this one -- for some reason it is regarded 
as an unknown region. Odd, as the test case right after this one works 
perfectly.


Repository:
  rC Clang

https://reviews.llvm.org/D50892



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50904: [analyzer][UninitializedObjectChecker] Added documentation to the checker list

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: george.karpenkov, NoQ, rnkovacs, xazax.hun.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

I'm not too sure that this aligns with the very short descriptions of other 
checkers, but I don't see how I could squeeze it down more without losing 
readability.


Repository:
  rC Clang

https://reviews.llvm.org/D50904

Files:
  www/analyzer/alpha_checks.html

Index: www/analyzer/alpha_checks.html
===
--- www/analyzer/alpha_checks.html
+++ www/analyzer/alpha_checks.html
@@ -323,6 +323,118 @@
 };
 
 
+
+
+alpha.cplusplus.UninitializedObject
+(C++)
+This checker reports uninitialized fields in objects created
+after a constructor call. It doesn't only find direct uninitialized
+fields, but rather makes a deep inspection of the object,
+analyzing all of it's fields subfields. 
+The checker regards inherited fields as direct fields, so one
+will recieve warnings for uninitialized inherited data members
+as well. 
+
+It has several options:
+
+  
+"Pedantic" (boolean). If its not set or is set to false, the checker
+won't emit warnings for objects that don't have at least one initialized
+field. This may be set with 
+-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true.
+  
+  
+"NotesAsWarnings" (boolean). If set to true, the checker will emit a
+warning for each uninitalized field, as opposed to emitting one warning
+per constructor call, and listing the uninitialized fields that belongs
+to it in notes. Defaults to false. 
+-analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true.
+  
+  
+"CheckPointeeInitialization" (boolean). If set to false, the checker will
+not analyze the pointee of pointer/reference fields, and will only check
+whether the object itself is initialized. Defaults to false. 
+-analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true.
+  
+
+
+
+// With Pedantic and CheckPointeeInitialization set to true
+
+struct A {
+  struct B {
+int x; // note: uninitialized field 'this->b.x'
+   // note: uninitialized field 'this->bptr->x'
+int y; // note: uninitialized field 'this->b.y'
+   // note: uninitialized field 'this->bptr->y'
+  };
+  int *iptr; // note: uninitialized pointer 'this->iptr'
+  B b;
+  B *bptr;
+  char *cptr; // note: uninitialized pointee 'this->cptr'
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // warning: 6 uninitialized fields
+   //  after the constructor call
+}
+
+
+// With Pedantic set to false and
+// CheckPointeeInitialization set to true
+// (every field is uninitialized)
+
+struct A {
+  struct B {
+int x;
+int y;
+  };
+  int *iptr;
+  B b;
+  B *bptr;
+  char *cptr;
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // no warning
+}
+
+
+// With Pedantic and CheckPointeeInitialization set to false
+// (pointees are regarded as initialized)
+
+struct A {
+  struct B {
+int x; // note: uninitialized field 'this->b.x'
+int y; // note: uninitialized field 'this->b.y'
+  };
+  int *iptr; // note: uninitialized pointer 'this->iptr'
+  B b;
+  B *bptr;
+  char *cptr;
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // warning: 3 uninitialized fields
+   //  after the constructor call
+}
+
+
+
+
+
 
 
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50904: [analyzer][UninitializedObjectChecker] Added documentation to the checker list

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 161262.
Szelethus added a comment.

Removed a TODO from the checker file.


https://reviews.llvm.org/D50904

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  www/analyzer/alpha_checks.html

Index: www/analyzer/alpha_checks.html
===
--- www/analyzer/alpha_checks.html
+++ www/analyzer/alpha_checks.html
@@ -323,6 +323,118 @@
 };
 
 
+
+
+alpha.cplusplus.UninitializedObject
+(C++)
+This checker reports uninitialized fields in objects created
+after a constructor call. It doesn't only find direct uninitialized
+fields, but rather makes a deep inspection of the object,
+analyzing all of it's fields subfields. 
+The checker regards inherited fields as direct fields, so one
+will recieve warnings for uninitialized inherited data members
+as well. 
+
+It has several options:
+
+  
+"Pedantic" (boolean). If its not set or is set to false, the checker
+won't emit warnings for objects that don't have at least one initialized
+field. This may be set with 
+-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true.
+  
+  
+"NotesAsWarnings" (boolean). If set to true, the checker will emit a
+warning for each uninitalized field, as opposed to emitting one warning
+per constructor call, and listing the uninitialized fields that belongs
+to it in notes. Defaults to false. 
+-analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true.
+  
+  
+"CheckPointeeInitialization" (boolean). If set to false, the checker will
+not analyze the pointee of pointer/reference fields, and will only check
+whether the object itself is initialized. Defaults to false. 
+-analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true.
+  
+
+
+
+// With Pedantic and CheckPointeeInitialization set to true
+
+struct A {
+  struct B {
+int x; // note: uninitialized field 'this->b.x'
+   // note: uninitialized field 'this->bptr->x'
+int y; // note: uninitialized field 'this->b.y'
+   // note: uninitialized field 'this->bptr->y'
+  };
+  int *iptr; // note: uninitialized pointer 'this->iptr'
+  B b;
+  B *bptr;
+  char *cptr; // note: uninitialized pointee 'this->cptr'
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // warning: 6 uninitialized fields
+   //  after the constructor call
+}
+
+
+// With Pedantic set to false and
+// CheckPointeeInitialization set to true
+// (every field is uninitialized)
+
+struct A {
+  struct B {
+int x;
+int y;
+  };
+  int *iptr;
+  B b;
+  B *bptr;
+  char *cptr;
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // no warning
+}
+
+
+// With Pedantic and CheckPointeeInitialization set to false
+// (pointees are regarded as initialized)
+
+struct A {
+  struct B {
+int x; // note: uninitialized field 'this->b.x'
+int y; // note: uninitialized field 'this->b.y'
+  };
+  int *iptr; // note: uninitialized pointer 'this->iptr'
+  B b;
+  B *bptr;
+  char *cptr;
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // warning: 3 uninitialized fields
+   //  after the constructor call
+}
+
+
+
+
+
 
 
 
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -285,18 +285,6 @@
   }
 
   // Checking bases.
-  // FIXME: As of now, because of `willObjectBeAnalyzedLater`, objects whose
-  // type is a descendant of another type will emit warnings for uninitalized
-  // inherited members.
-  // This is not the only way to analyze bases of an object -- if we didn't
-  // filter them out, and didn't analyze the bases, this checker would run for
-  // each base of the object in order of base initailization and in theory would
-  // find every uninitalized field. This approach could also make handling
-  // diamond inheritances more easily.
-  //
-  // This rule (that a descendant type's cunstructor is responsible for
-  // initializing inherited data members) is not obvious, and should it should
-  // be.
   const auto *CXXRD = dyn_cast(RD);
   if (!CXXRD)
 return ContainsUninitField;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50905: [analyzer][UninitializedObjectChecker][WIP] Explicit namespace resolution for inherited data members

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: NoQ, george.karpenkov, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

For the following example:

  struct Base {
int x;
  };
  
  // In a different translation unit
  
  struct Derived : public Base {
Derived() {}
  };

For a call to `Derived::Derived()`, we'll receive a note that `this->x` is 
uninitialized. Since `x` is not a direct field of `Derived`, it could be a 
little confusing. This patch aims to fix this, we well as the case when the 
derived object has a field that has the name as an inherited uninitialized data 
member:

  struct Base {
int x; // note: uninitialized field 'this->Base::x'
  };
  
  struct Derived : public Base {
int x = 5;
Derived() {}
  };

This patch is also meant as a conversation starter, as the way base classes 
were handled has been long debated.


Repository:
  rC Clang

https://reviews.llvm.org/D50905

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp

Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -35,7 +35,7 @@
 }
 
 class NonPolymorphicBaseClass2 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonPolymorphicBaseClass2::x'}}
 protected:
   int y;
 
@@ -62,7 +62,7 @@
   int x;
 
 protected:
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->NonPolymorphicBaseClass3::y'}}
 public:
   NonPolymorphicBaseClass3() = default;
   NonPolymorphicBaseClass3(int) : x(7) {}
@@ -140,7 +140,7 @@
 }
 
 class PolymorphicRight1 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->PolymorphicRight1::x'}}
 protected:
   int y;
 
@@ -168,7 +168,7 @@
   int x;
 
 protected:
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->PolymorphicBaseClass3::y'}}
 public:
   virtual ~PolymorphicBaseClass3() = default;
   PolymorphicBaseClass3() = default;
@@ -248,7 +248,7 @@
 }
 
 class VirtualPolymorphicRight1 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->VirtualPolymorphicRight1::x'}}
 protected:
   int y;
 
@@ -276,7 +276,7 @@
   int x;
 
 protected:
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->VirtualPolymorphicBaseClass3::y'}}
 public:
   virtual ~VirtualPolymorphicBaseClass3() = default;
   VirtualPolymorphicBaseClass3() = default;
@@ -358,7 +358,7 @@
   Left2(int) : x(36) {}
 };
 struct Right2 {
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->Right2::y'}}
   Right2() = default;
   Right2(int) : y(37) {}
 };
@@ -378,7 +378,7 @@
 }
 
 struct Left3 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->Left3::x'}}
   Left3() = default;
   Left3(int) : x(39) {}
 };
@@ -433,7 +433,7 @@
   Left5(int) : x(44) {}
 };
 struct Right5 {
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->Right5::y'}}
   Right5() = default;
   Right5(int) : y(45) {}
 };
@@ -514,7 +514,7 @@
 }
 
 struct NonVirtualBase2 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase2::x'}}
   NonVirtualBase2() = default;
   NonVirtualBase2(int) : x(52) {}
 };
@@ -542,7 +542,7 @@
 }
 
 struct NonVirtualBase3 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase3::x'}}
   NonVirtualBase3() = default;
   NonVirtualBase3(int) : x(54) {}
 };
@@ -570,8 +570,8 @@
 }
 
 struct NonVirtualBase4 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
-  // expected-note@-1{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase4::x'}}
+  // expected-note@-1{{uninitialized field 'this->NonVirtualBase4::x'}}
   NonVirtualBase4() = default;
   NonVirtualBase4(int) : x(56) {}
 };
@@ -626,7 +626,7 @@
 }
 
 struct NonVirtualBase6 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase6::x'}}
   NonVirtualBase6() = default;
   NonVirtualBase6(int) : x(59) {}
 };
@@ -712,7 +712,7 @@
 }
 
 struct VirtualBase2 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expec

[PATCH] D50904: [analyzer][UninitializedObjectChecker] Added documentation to the checker list

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: www/analyzer/alpha_checks.html:334-336
+The checker regards inherited fields as direct fields, so one
+will recieve warnings for uninitialized inherited data members
+as well. 

This statement has been debated for a while, so I'm all for discussing it, as I 
feel I've gained a lot more knowledge about this subject since it was last 
mentioned.


https://reviews.llvm.org/D50904



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50488: [Analyzer] Checker for non-determinism caused by sorting of pointer-like keys

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp:72-76
+  auto IteratesPointerKeysM = hasType(cxxRecordDecl(has(
+fieldDecl(hasType(hasCanonicalType(
+  pointsTo(hasCanonicalType(pointerType()))
+)))
+  )));

Szelethus wrote:
> I'm not a matcher-expert, but here we go:
> 
> As I understand it, you're matching iterator objects that wrap a pointer to 
> pointer. Would it match this case?:
> 
> ```
> void fill(int **IntPointerArray);
> 
> int main() {
>   int *IntPointerArray[20]; // or a simple int array
>   fill(IntPointerArray);
> 
>   std::sort(IntPointerArray, IntPointerArray + 20);
> }
> ```
> `int**` is an [[ 
> https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator | 
> RandomAccessIterator ]], but is not a `CXXRecordDecl`. As I mentioned 
> earlier, it might be worth taking a look at `hasType`, and attempt to acquire 
> `value_type`, as it is required for STL algorithms (it could be in a base 
> class as well). `value_type` is also predefined through 
> `std::iterator_traits` for pointer iterators like `int**`.
Also, this could lead to false positives, as iterators may store pointers to 
pointers that don't compare memory addresses. And it could maybe cause false 
negatives, if the `value_type` is a pointer type but the elements are stored in 
wrappers.

As I understand it.


https://reviews.llvm.org/D50488



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50904: [analyzer][UninitializedObjectChecker] Added documentation to the checker list

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: www/analyzer/alpha_checks.html:334-336
+The checker regards inherited fields as direct fields, so one
+will recieve warnings for uninitialized inherited data members
+as well. 

NoQ wrote:
> Szelethus wrote:
> > This statement has been debated for a while, so I'm all for discussing it, 
> > as I feel I've gained a lot more knowledge about this subject since it was 
> > last mentioned.
> The documentation should still reflect the //actual// state of things, right?
Yes :)


https://reviews.llvm.org/D50904



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50509: [analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp:223
+  // int*).
+  while (auto Tmp = V.getAs()) {
+// We can't reason about symbolic regions, assume its initialized.

NoQ wrote:
> Hmm, i still have concerns about things like `int *x = (int *)&x;`. Why not 
> just check the type to terminate the loop? Type hierarchy is guaranteed to be 
> finite.
There actually is a testcase for that -- it would create a 
nonloc::LocAsInteger, not a loc::MemRegionVal.

I'll add a TODO to revisit this loop condition (again :) ).


https://reviews.llvm.org/D50509



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50509: [analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function

2018-08-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp:223
+  // int*).
+  while (auto Tmp = V.getAs()) {
+// We can't reason about symbolic regions, assume its initialized.

NoQ wrote:
> Szelethus wrote:
> > NoQ wrote:
> > > Hmm, i still have concerns about things like `int *x = (int *)&x;`. Why 
> > > not just check the type to terminate the loop? Type hierarchy is 
> > > guaranteed to be finite.
> > There actually is a testcase for that -- it would create a 
> > nonloc::LocAsInteger, not a loc::MemRegionVal.
> > 
> > I'll add a TODO to revisit this loop condition (again :) ).
> Ok, let's try with one more asterisk:
> ```
> 1 void test() {
> 2   int **x = (int **)&x;
> 3   int *y = *x;
> 4   int z = *y;
> 5 }
> ```
> 
> Here's what i get in the Store:
> ```
> (x,0,direct) : &element{x,0 S64b,int *}
> (y,0,direct) : &element{x,0 S64b,int *}
> (z,0,direct) : &element{x,0 S64b,int *}
> ```
Sounds fun, I'll see how the checker behaves to these when I'm in the office.


https://reviews.llvm.org/D50509



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50963: [NFC] Don't define static function in header (UninitializedObject.h)

2018-08-20 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus accepted this revision.
Szelethus added a comment.
This revision is now accepted and ready to land.

Thanks! Learned something new today then :) This solution looks a lot cleaner 
as well.


https://reviews.llvm.org/D50963



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50509: [analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function

2018-08-21 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp:223
+  // int*).
+  while (auto Tmp = V.getAs()) {
+// We can't reason about symbolic regions, assume its initialized.

Szelethus wrote:
> NoQ wrote:
> > Szelethus wrote:
> > > NoQ wrote:
> > > > Hmm, i still have concerns about things like `int *x = (int *)&x;`. Why 
> > > > not just check the type to terminate the loop? Type hierarchy is 
> > > > guaranteed to be finite.
> > > There actually is a testcase for that -- it would create a 
> > > nonloc::LocAsInteger, not a loc::MemRegionVal.
> > > 
> > > I'll add a TODO to revisit this loop condition (again :) ).
> > Ok, let's try with one more asterisk:
> > ```
> > 1 void test() {
> > 2   int **x = (int **)&x;
> > 3   int *y = *x;
> > 4   int z = *y;
> > 5 }
> > ```
> > 
> > Here's what i get in the Store:
> > ```
> > (x,0,direct) : &element{x,0 S64b,int *}
> > (y,0,direct) : &element{x,0 S64b,int *}
> > (z,0,direct) : &element{x,0 S64b,int *}
> > ```
> Sounds fun, I'll see how the checker behaves to these when I'm in the office.
Yup, you were correct, it ends up in an infinite loop. I'll add the testcase 
for it before commiting.


https://reviews.llvm.org/D50509



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50509: [analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function

2018-08-21 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rL340265: [analyzer][UninitializedObjectChecker] Refactoring 
p6.: Move dereferencing to a… (authored by Szelethus, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D50509?vs=161209&id=161685#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D50509

Files:
  
cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  
cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -265,7 +265,8 @@
   continue;
 }
 
-if (T->isAnyPointerType() || T->isReferenceType() || T->isBlockPointerType()) {
+if (T->isAnyPointerType() || T->isReferenceType() ||
+T->isBlockPointerType()) {
   if (isPointerOrReferenceUninit(FR, LocalChain))
 ContainsUninitField = true;
   continue;
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -95,6 +95,12 @@
 /// known, and thus FD can not be analyzed.
 static bool isVoidPointer(QualType T);
 
+/// Dereferences \p V and returns the value and dynamic type of the pointee, as
+/// well as wether \p FR needs to be casted back to that type. If for whatever
+/// reason dereferencing fails, returns with None.
+static llvm::Optional>
+dereference(ProgramStateRef State, const FieldRegion *FR);
+
 //===--===//
 //   Methods for FindUninitializedFields.
 //===--===//
@@ -126,67 +132,22 @@
 return false;
   }
 
-  assert(V.getAs() &&
- "At this point V must be loc::MemRegionVal!");
-  auto L = V.castAs();
-
-  // We can't reason about symbolic regions, assume its initialized.
-  // Note that this also avoids a potential infinite recursion, because
-  // constructors for list-like classes are checked without being called, and
-  // the Static Analyzer will construct a symbolic region for Node *next; or
-  // similar code snippets.
-  if (L.getRegion()->getSymbolicBase()) {
-IsAnyFieldInitialized = true;
-return false;
-  }
-
-  DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
-  if (!DynTInfo.isValid()) {
+  // At this point the pointer itself is initialized and points to a valid
+  // location, we'll now check the pointee.
+  llvm::Optional> DerefInfo =
+  dereference(State, FR);
+  if (!DerefInfo) {
 IsAnyFieldInitialized = true;
 return false;
   }
 
-  QualType DynT = DynTInfo.getType();
-
-  // If the static type of the field is a void pointer, we need to cast it back
-  // to the dynamic type before dereferencing.
-  bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
-
-  if (isVoidPointer(DynT)) {
-IsAnyFieldInitialized = true;
-return false;
-  }
-
-  // At this point the pointer itself is initialized and points to a valid
-  // location, we'll now check the pointee.
-  SVal DerefdV = State->getSVal(V.castAs(), DynT);
-
-  // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
-  // int** -> int*).
-  while (auto Tmp = DerefdV.getAs()) {
-if (Tmp->getRegion()->getSymbolicBase()) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
-if (!DynTInfo.isValid()) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DynT = DynTInfo.getType();
-if (isVoidPointer(DynT)) {
-  IsAnyFieldInitialized = true;
-  return false;
-}
-
-DerefdV = State->getSVal(*Tmp, DynT);
-  }
+  V = std::get<0>(*DerefInfo);
+  QualType DynT = std::get<1>(*DerefInfo);
+  bool NeedsCastBack = std::get<2>(*DerefInfo);
 
   // If FR is a pointer pointing to a non-primitive type.
   if (Optional RecordV =
-  DerefdV.getAs()) {
+  V.getAs()) {
 
 const TypedValueRegion *R = RecordV->getRegion();
 
@@ -220,7 +181,7 @@
  "At this point FR must either have a primitive dynamic type, or it "
  "must be a null, undefined, unknown or concrete pointer!");
 
-  if (isPrimitiveUninit(DerefdV)) {
+  if (isPrimitiveUninit(V)) {

[PATCH] D50904: [analyzer][UninitializedObjectChecker] Added documentation to the checker list

2018-08-21 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL340266: [analyzer][UninitializedObjectChecker] Added 
documentation to the checker list (authored by Szelethus, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D50904?vs=161262&id=161686#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D50904

Files:
  
cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  cfe/trunk/www/analyzer/alpha_checks.html

Index: cfe/trunk/www/analyzer/alpha_checks.html
===
--- cfe/trunk/www/analyzer/alpha_checks.html
+++ cfe/trunk/www/analyzer/alpha_checks.html
@@ -323,6 +323,118 @@
 };
 
 
+
+
+alpha.cplusplus.UninitializedObject
+(C++)
+This checker reports uninitialized fields in objects created
+after a constructor call. It doesn't only find direct uninitialized
+fields, but rather makes a deep inspection of the object,
+analyzing all of it's fields subfields. 
+The checker regards inherited fields as direct fields, so one
+will recieve warnings for uninitialized inherited data members
+as well. 
+
+It has several options:
+
+  
+"Pedantic" (boolean). If its not set or is set to false, the checker
+won't emit warnings for objects that don't have at least one initialized
+field. This may be set with 
+-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true.
+  
+  
+"NotesAsWarnings" (boolean). If set to true, the checker will emit a
+warning for each uninitalized field, as opposed to emitting one warning
+per constructor call, and listing the uninitialized fields that belongs
+to it in notes. Defaults to false. 
+-analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true.
+  
+  
+"CheckPointeeInitialization" (boolean). If set to false, the checker will
+not analyze the pointee of pointer/reference fields, and will only check
+whether the object itself is initialized. Defaults to false. 
+-analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true.
+  
+
+
+
+// With Pedantic and CheckPointeeInitialization set to true
+
+struct A {
+  struct B {
+int x; // note: uninitialized field 'this->b.x'
+   // note: uninitialized field 'this->bptr->x'
+int y; // note: uninitialized field 'this->b.y'
+   // note: uninitialized field 'this->bptr->y'
+  };
+  int *iptr; // note: uninitialized pointer 'this->iptr'
+  B b;
+  B *bptr;
+  char *cptr; // note: uninitialized pointee 'this->cptr'
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // warning: 6 uninitialized fields
+   //  after the constructor call
+}
+
+
+// With Pedantic set to false and
+// CheckPointeeInitialization set to true
+// (every field is uninitialized)
+
+struct A {
+  struct B {
+int x;
+int y;
+  };
+  int *iptr;
+  B b;
+  B *bptr;
+  char *cptr;
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // no warning
+}
+
+
+// With Pedantic and CheckPointeeInitialization set to false
+// (pointees are regarded as initialized)
+
+struct A {
+  struct B {
+int x; // note: uninitialized field 'this->b.x'
+int y; // note: uninitialized field 'this->b.y'
+  };
+  int *iptr; // note: uninitialized pointer 'this->iptr'
+  B b;
+  B *bptr;
+  char *cptr;
+
+  A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+  A::B b;
+  char c;
+  A a(&b, &c); // warning: 3 uninitialized fields
+   //  after the constructor call
+}
+
+
+
+
+
 
 
 
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -286,18 +286,6 @@
   }
 
   // Checking bases.
-  // FIXME: As of now, because of `willObjectBeAnalyzedLater`, objects whose
-  // type is a descendant of another type will emit warnings for uninitalized
-  // inherited members.
-  // This is not the only way to analyze bases of an object -- if we didn't
-  // filter them out, and didn't analyze the bases, this checker would run for
-  // each base of the object in order of base initailization and in theory would
-  // find every uninitalized field. This approach could also make handling
-  // diamond inheritances more easily.
-  //
-  // This rule (that a descendant type's cunstructor is responsible for
-  // initializing inherited data members) is not obvious, and should it should
-  // be.
   const auto *CXXRD = dyn_cast(RD);
   if (!CXXRD)
 return ContainsUninitField;
___
cf

[PATCH] D50488: [Analyzer] Checker for non-determinism caused by sorting of pointer-like keys

2018-08-21 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

In https://reviews.llvm.org/D50488#1204655, @mgrang wrote:

> In https://reviews.llvm.org/D50488#1203876, @Szelethus wrote:
>
> >
>
>
> This is my first time with ASTMatchers and I am not sure how to get the 
> value_type from hasType (I don't see a matcher for value_types in 
> ASTMatchers.h). Would I end up using a visitor for that? If yes, then maybe 
> the entire check for pointer types needs to be done via visitors? Sorry for 
> the newbie questions :)


I played around for a bit, my `clang-query` is a little out of date, but here's 
what I found: You can match `typedef`s with `typedefDecl()`, and `using` by 
`typeAliasDecl()`, and then add `hasName("value_type")` as a parameter. As to 
how to check whether a type has any of these, I'm a little unsure myself, but 
you could use `hasDescendant`, and narrow down the matches.

I'm not sure whether this checks inherited type declarations, and it sure 
doesn't check template specializations of `std::iterator_traits`, but it is a 
good start :) I'll revisit this when I have a little more time on my hand.


https://reviews.llvm.org/D50488



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50905: [analyzer][UninitializedObjectChecker] Explicit namespace resolution for inherited data members

2018-08-21 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC340272: [analyzer][UninitializedObjectChecker] Explicit 
namespace resolution for… (authored by Szelethus, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D50905?vs=161271&id=161700#toc

Repository:
  rC Clang

https://reviews.llvm.org/D50905

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp

Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -35,7 +35,7 @@
 }
 
 class NonPolymorphicBaseClass2 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonPolymorphicBaseClass2::x'}}
 protected:
   int y;
 
@@ -62,7 +62,7 @@
   int x;
 
 protected:
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->NonPolymorphicBaseClass3::y'}}
 public:
   NonPolymorphicBaseClass3() = default;
   NonPolymorphicBaseClass3(int) : x(7) {}
@@ -140,7 +140,7 @@
 }
 
 class PolymorphicRight1 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->PolymorphicRight1::x'}}
 protected:
   int y;
 
@@ -168,7 +168,7 @@
   int x;
 
 protected:
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->PolymorphicBaseClass3::y'}}
 public:
   virtual ~PolymorphicBaseClass3() = default;
   PolymorphicBaseClass3() = default;
@@ -248,7 +248,7 @@
 }
 
 class VirtualPolymorphicRight1 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->VirtualPolymorphicRight1::x'}}
 protected:
   int y;
 
@@ -276,7 +276,7 @@
   int x;
 
 protected:
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->VirtualPolymorphicBaseClass3::y'}}
 public:
   virtual ~VirtualPolymorphicBaseClass3() = default;
   VirtualPolymorphicBaseClass3() = default;
@@ -358,7 +358,7 @@
   Left2(int) : x(36) {}
 };
 struct Right2 {
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->Right2::y'}}
   Right2() = default;
   Right2(int) : y(37) {}
 };
@@ -378,7 +378,7 @@
 }
 
 struct Left3 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->Left3::x'}}
   Left3() = default;
   Left3(int) : x(39) {}
 };
@@ -433,7 +433,7 @@
   Left5(int) : x(44) {}
 };
 struct Right5 {
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->Right5::y'}}
   Right5() = default;
   Right5(int) : y(45) {}
 };
@@ -514,7 +514,7 @@
 }
 
 struct NonVirtualBase2 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase2::x'}}
   NonVirtualBase2() = default;
   NonVirtualBase2(int) : x(52) {}
 };
@@ -542,7 +542,7 @@
 }
 
 struct NonVirtualBase3 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase3::x'}}
   NonVirtualBase3() = default;
   NonVirtualBase3(int) : x(54) {}
 };
@@ -570,8 +570,8 @@
 }
 
 struct NonVirtualBase4 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
-  // expected-note@-1{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase4::x'}}
+  // expected-note@-1{{uninitialized field 'this->NonVirtualBase4::x'}}
   NonVirtualBase4() = default;
   NonVirtualBase4(int) : x(56) {}
 };
@@ -626,7 +626,7 @@
 }
 
 struct NonVirtualBase6 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase6::x'}}
   NonVirtualBase6() = default;
   NonVirtualBase6(int) : x(59) {}
 };
@@ -712,7 +712,7 @@
 }
 
 struct VirtualBase2 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->VirtualBase2::x'}}
   VirtualBase2() = default;
   VirtualBase2(int) : x(63) {}
 };
@@ -751,7 +751,7 @@
 }
 
 struct VirtualBase3 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->VirtualBase3::x'}}
   VirtualBase3() = default;
   VirtualBase3(int) : x(66) {}
 };
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers

[PATCH] D50905: [analyzer][UninitializedObjectChecker] Explicit namespace resolution for inherited data members

2018-08-21 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL340272: [analyzer][UninitializedObjectChecker] Explicit 
namespace resolution for… (authored by Szelethus, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D50905?vs=161271&id=161701#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D50905

Files:
  
cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  
cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp

Index: cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ cfe/trunk/test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -35,7 +35,7 @@
 }
 
 class NonPolymorphicBaseClass2 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonPolymorphicBaseClass2::x'}}
 protected:
   int y;
 
@@ -62,7 +62,7 @@
   int x;
 
 protected:
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->NonPolymorphicBaseClass3::y'}}
 public:
   NonPolymorphicBaseClass3() = default;
   NonPolymorphicBaseClass3(int) : x(7) {}
@@ -140,7 +140,7 @@
 }
 
 class PolymorphicRight1 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->PolymorphicRight1::x'}}
 protected:
   int y;
 
@@ -168,7 +168,7 @@
   int x;
 
 protected:
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->PolymorphicBaseClass3::y'}}
 public:
   virtual ~PolymorphicBaseClass3() = default;
   PolymorphicBaseClass3() = default;
@@ -248,7 +248,7 @@
 }
 
 class VirtualPolymorphicRight1 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->VirtualPolymorphicRight1::x'}}
 protected:
   int y;
 
@@ -276,7 +276,7 @@
   int x;
 
 protected:
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->VirtualPolymorphicBaseClass3::y'}}
 public:
   virtual ~VirtualPolymorphicBaseClass3() = default;
   VirtualPolymorphicBaseClass3() = default;
@@ -358,7 +358,7 @@
   Left2(int) : x(36) {}
 };
 struct Right2 {
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->Right2::y'}}
   Right2() = default;
   Right2(int) : y(37) {}
 };
@@ -378,7 +378,7 @@
 }
 
 struct Left3 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->Left3::x'}}
   Left3() = default;
   Left3(int) : x(39) {}
 };
@@ -433,7 +433,7 @@
   Left5(int) : x(44) {}
 };
 struct Right5 {
-  int y; // expected-note{{uninitialized field 'this->y'}}
+  int y; // expected-note{{uninitialized field 'this->Right5::y'}}
   Right5() = default;
   Right5(int) : y(45) {}
 };
@@ -514,7 +514,7 @@
 }
 
 struct NonVirtualBase2 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase2::x'}}
   NonVirtualBase2() = default;
   NonVirtualBase2(int) : x(52) {}
 };
@@ -542,7 +542,7 @@
 }
 
 struct NonVirtualBase3 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase3::x'}}
   NonVirtualBase3() = default;
   NonVirtualBase3(int) : x(54) {}
 };
@@ -570,8 +570,8 @@
 }
 
 struct NonVirtualBase4 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
-  // expected-note@-1{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase4::x'}}
+  // expected-note@-1{{uninitialized field 'this->NonVirtualBase4::x'}}
   NonVirtualBase4() = default;
   NonVirtualBase4(int) : x(56) {}
 };
@@ -626,7 +626,7 @@
 }
 
 struct NonVirtualBase6 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->NonVirtualBase6::x'}}
   NonVirtualBase6() = default;
   NonVirtualBase6(int) : x(59) {}
 };
@@ -712,7 +712,7 @@
 }
 
 struct VirtualBase2 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->VirtualBase2::x'}}
   VirtualBase2() = default;
   VirtualBase2(int) : x(63) {}
 };
@@ -751,7 +751,7 @@
 }
 
 struct VirtualBase3 {
-  int x; // expected-note{{uninitialized field 'this->x'}}
+  int x; // expected-note{{uninitialized field 'this->VirtualBase3::x'}}
   VirtualBase3() = default;
   VirtualBase3(int) : x(66) {}
 };
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--

[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-08-21 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: NoQ, george.karpenkov, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

This patch aims to fix derefencing, which has been debated for months now.

Instead of working with `SVal`s, the function now relies on `TypedValueRegion`.

Since this has been discussed since the inception of the checker, I'd very much 
prefer finding a permanent solution for this before moving forward.


Repository:
  rC Clang

https://reviews.llvm.org/D51057

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -203,18 +203,14 @@
   CyclicPointerTest1();
 }
 
-// TODO: Currently, the checker ends up in an infinite loop for the following
-// test case.
-/*
 struct CyclicPointerTest2 {
-  int **pptr;
+  int **pptr; // no-crash
   CyclicPointerTest2() : pptr(reinterpret_cast(&pptr)) {}
 };
 
 void fCyclicPointerTest2() {
   CyclicPointerTest2();
 }
-*/
 
 //===--===//
 // Void pointer tests.
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -95,11 +95,13 @@
 /// known, and thus FD can not be analyzed.
 static bool isVoidPointer(QualType T);
 
-/// Dereferences \p V and returns the value and dynamic type of the pointee, as
-/// well as wether \p FR needs to be casted back to that type. If for whatever
-/// reason dereferencing fails, returns with None.
-static llvm::Optional>
-dereference(ProgramStateRef State, const FieldRegion *FR);
+using DereferenceInfo = std::pair;
+
+/// Dereferences \p FR and returns with the pointee's region, and whether it
+/// needs to be casted back to it's location type. If for whatever reason
+/// dereferencing fails, returns with None.
+static llvm::Optional dereference(ProgramStateRef State,
+   const FieldRegion *FR);
 
 //===--===//
 //   Methods for FindUninitializedFields.
@@ -110,9 +112,7 @@
 bool FindUninitializedFields::isPointerOrReferenceUninit(
 const FieldRegion *FR, FieldChainInfo LocalChain) {
 
-  assert((FR->getDecl()->getType()->isAnyPointerType() ||
-  FR->getDecl()->getType()->isReferenceType() ||
-  FR->getDecl()->getType()->isBlockPointerType()) &&
+  assert(isLocType(FR->getDecl()->getType()) &&
  "This method only checks pointer/reference objects!");
 
   SVal V = State->getSVal(FR);
@@ -123,6 +123,8 @@
   }
 
   if (V.isUndef()) {
+assert(!FR->getDecl()->getType()->isReferenceType() &&
+   "References must be initialized!");
 return addFieldToUninits(
 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
   }
@@ -134,54 +136,46 @@
 
   // At this point the pointer itself is initialized and points to a valid
   // location, we'll now check the pointee.
-  llvm::Optional> DerefInfo =
-  dereference(State, FR);
+  llvm::Optional DerefInfo = dereference(State, FR);
   if (!DerefInfo) {
 IsAnyFieldInitialized = true;
 return false;
   }
 
-  V = std::get<0>(*DerefInfo);
-  QualType DynT = std::get<1>(*DerefInfo);
-  bool NeedsCastBack = std::get<2>(*DerefInfo);
+  const TypedValueRegion *R = DerefInfo->first;
+  const bool NeedsCastBack = DerefInfo->second;
 
-  // If FR is a pointer pointing to a non-primitive type.
-  if (Optional RecordV =
-  V.getAs()) {
+  QualType DynT = R->getLocationType();
+  QualType PointeeT = DynT->getPointeeType();
 
-const TypedValueRegion *R = RecordV->getRegion();
+  if (PointeeT->isStructureOrClassType()) {
+if (NeedsCastBack)
+  return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
+return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
+  }
 
-if (DynT->getPointeeType()->isStructureOrClassType()) {
+  if (PointeeT->isUnionType()) {
+if (isUnionUninit(R)) {
   if (NeedsCastBack)
-return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
-  return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
-}
-
-if (DynT->getPointeeType()->isUnionType()) {
-  if (isUnionUninit(R)) {
-if (NeedsCastBack)
-  return addFieldToUninits(LocalChain.add(NeedsCastL

[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-08-21 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp:187-191
   // If FR is a pointer pointing to a non-primitive type.
   if (Optional RecordV =
   DerefdV.getAs()) {
 
 const TypedValueRegion *R = RecordV->getRegion();

NoQ wrote:
> This looks like one more situation where we dereference a location to get a 
> value and then struggle to get back to the location that we've dereferenced 
> by looking at the value. Can we just use `V`?
I've struggled with derefencing for months now -- I'm afraid I just don't 
really get what you'd like to see here.

Here's what I attempted to implement:
I'd like to obtain the pointee's region of a `Loc` region, even if it has to be 
casted to another type, like through void pointers and `nonloc::LocAsInteger`, 
and continue analysis on said region as usual.

The trickiest part I can't seem to get right is the acquisition of the pointee 
region. For the problem this patch attempts to solve, even though `DynT` 
correctly says that the dynamic type is `DynTDerived2 *`, `DerefdV` contains a 
region for `DynTBase`.

I uploaded a new patch, D51057, which hopefully settles derefence related 
issues. Please note that it **does not **replace this diff, as the acquired 
region is still of type `DynTBase`.

I find understanding these intricate details of the analyzer very difficult, as 
I found very little documentation about how this works, which often left me 
guessing what the proper way to do this is. Can you recommend some literature 
for me on this field?


Repository:
  rC Clang

https://reviews.llvm.org/D50892



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-08-21 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

@NoQ, is this how you imagined derefercing to work? I'm still a little 
uncertain that I implemented this in a way that addresses all your concerns.


Repository:
  rC Clang

https://reviews.llvm.org/D51057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45532: [StaticAnalyzer] Checker to find uninitialized fields after a constructor call

2018-05-15 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

I'm afraid it'll be even more time before I post a new diff. There are some 
things that `ProgramState` is lacking, so I'll get that fixed first in a 
different pull request first.




Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:258-260
+Report->addNote(NoteBuf,
+PathDiagnosticLocation::create(FieldChain.getEndOfChain(),
+   
Context.getSourceManager()));

NoQ wrote:
> NoQ wrote:
> > Szelethus wrote:
> > > NoQ wrote:
> > > > Aha, ok, got it, so you're putting the warning at the end of the 
> > > > constructor and squeezing all uninitialized fields into a single 
> > > > warning by presenting them as notes.
> > > > 
> > > > Because for now notes aren't supported everywhere (and aren't always 
> > > > supported really well), i guess it'd be necessary to at least provide 
> > > > an option to make note-less reports before the checker is enabled by 
> > > > default everywhere. In this case notes contain critical pieces of 
> > > > information and as such cannot be really discarded.
> > > > 
> > > > I'm not sure that notes are providing a better user experience here 
> > > > than simply saying that "field x.y->z is never initialized". With 
> > > > notes, the user will have to scroll around (at least in scan-build) to 
> > > > find which field is uninitialized.
> > > > 
> > > > Notes will probably also not decrease the number of reports too much 
> > > > because in most cases there will be just one uninitialized field. 
> > > > Though i agree that when there is more than one report, the user will 
> > > > be likely to deal with all fields at once rather than separately.
> > > > 
> > > > So it's a bit wonky.
> > > > 
> > > > We might want to enable one mode or another in the checker depending on 
> > > > the analyzer output flag. Probably in the driver 
> > > > (`RenderAnalyzerOptions()`).
> > > > 
> > > > It'd be a good idea to land the checker into alpha first and fix this 
> > > > in a follow-up patch because this review is already overweight.
> > > > [...]i guess it'd be necessary to at least provide an option to make 
> > > > note-less reports before the checker is enabled by default everywhere. 
> > > > In this case notes contain critical pieces of information and as such 
> > > > cannot be really discarded.
> > > This can already be achieved with `-analyzer-config 
> > > notes-as-events=true`. There no good reason however not to make an 
> > > additional flag that would emit warnings instead of notes.
> > > > I'm not sure that notes are providing a better user experience here 
> > > > than simply saying that "field x.y->z is never initialized". With 
> > > > notes, the user will have to scroll around (at least in scan-build) to 
> > > > find which field is uninitialized.
> > > This checker had a previous implementation that emitted a warning for 
> > > each uninitialized field, instead of squeezing them in a single warning 
> > > per constructor call. One of the major reasons behind rewriting it was 
> > > that it emitted so many of them that it was difficult to differentiate 
> > > which warning belonged to which constructor call. Also, in the case of 
> > > the LLVM/Clang project, the warnings from this checker alone would be in 
> > > the thousands.
> > > > Notes will probably also not decrease the number of reports too much 
> > > > because in most cases there will be just one uninitialized field.
> > > While this is true to some extent, it's not uncommon that a single 
> > > constructor call leaves 7 uninitialized -- in the LLVM/Clang project I 
> > > found one that had over 30!
> > > Since its practically impossible to determine whether this was a 
> > > performance enhancement or just poor programming, the few cases where it 
> > > is intentional, an object would emit many more warnings would make  make 
> > > majority of the findings (where an object truly had only 1 or 2 fields 
> > > uninit) a lot harder to spot in my opinion.
> > > 
> > > In general, I think one warning per constructor call makes the best user 
> > > experience, but a temporary solution should be implemented until there's 
> > > better support for notes.
> > > 
> > > I agree, this should be a topic of a follow-up patch.
> > > 
> > > This can already be achieved with `-analyzer-config notes-as-events=true`.
> > 
> > Yep. But the resulting user experience seems pretty bad to me. It was a 
> > good quick proof-of-concept trick to test things, but the fact that notes 
> > aren't path pieces is way too apparent in case of this checker. So i guess 
> > this flag was a bad idea.
> > 
> > > Also, in the case of the LLVM/Clang project, the warnings from this 
> > > checker alone would be in the thousands.
> > 
> > This makes me a bit worried, i wonder what's the reason why does the 
> > checker shout so loudly on a codebase that doesn't seem to have actual 
> > uninitialized value

[PATCH] D46891: [StaticAnalyzer] Added a getLValue method to ProgramState for bases

2018-05-15 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: xazax.hun, NoQ.
Herald added subscribers: cfe-commits, a.sidorin, rnkovacs, szepet, whisperity.
Herald added a reviewer: george.karpenkov.

Repository:
  rC Clang

https://reviews.llvm.org/D46891

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h


Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -294,6 +294,9 @@
   ProgramStateRef enterStackFrame(const CallEvent &Call,
   const StackFrameContext *CalleeCtx) const;
 
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) 
const;
+
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
 
@@ -724,6 +727,14 @@
   return this;
 }
 
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+   const SubRegion *Super) const {
+  const auto Base = BaseSpec.getType()->getAsCXXRecordDecl();
+  return loc::MemRegionVal(
+  getStateManager().getRegionManager().getCXXBaseObjectRegion(
+Base, Super, 
BaseSpec.isVirtual()));
+}
+
 inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
   return getStateManager().StoreMgr->getLValueVar(VD, LC);


Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -294,6 +294,9 @@
   ProgramStateRef enterStackFrame(const CallEvent &Call,
   const StackFrameContext *CalleeCtx) const;
 
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const;
+
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
 
@@ -724,6 +727,14 @@
   return this;
 }
 
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+   const SubRegion *Super) const {
+  const auto Base = BaseSpec.getType()->getAsCXXRecordDecl();
+  return loc::MemRegionVal(
+  getStateManager().getRegionManager().getCXXBaseObjectRegion(
+Base, Super, BaseSpec.isVirtual()));
+}
+
 inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
   return getStateManager().StoreMgr->getLValueVar(VD, LC);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46891: [StaticAnalyzer] Added a getLValue method to ProgramState for bases

2018-05-16 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 147033.
Szelethus edited the summary of this revision.
Szelethus added a comment.

Added a `CXXRecordDecl` version.


https://reviews.llvm.org/D46891

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h


Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -294,6 +294,13 @@
   ProgramStateRef enterStackFrame(const CallEvent &Call,
   const StackFrameContext *CalleeCtx) const;
 
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) 
const;
+
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
+bool isVirtual) const;
+
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
 
@@ -724,6 +731,22 @@
   return this;
 }
 
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+   const SubRegion *Super) const {
+  const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
+  return loc::MemRegionVal(
+  getStateManager().getRegionManager().getCXXBaseObjectRegion(
+Base, Super, 
BaseSpec.isVirtual()));
+}
+
+inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass,
+   const SubRegion *Super,
+   bool isVirtual) const {
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+  BaseClass, Super, 
isVirtual));
+}
+
 inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
   return getStateManager().StoreMgr->getLValueVar(VD, LC);


Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -294,6 +294,13 @@
   ProgramStateRef enterStackFrame(const CallEvent &Call,
   const StackFrameContext *CalleeCtx) const;
 
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const;
+
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
+bool isVirtual) const;
+
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
 
@@ -724,6 +731,22 @@
   return this;
 }
 
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+   const SubRegion *Super) const {
+  const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
+  return loc::MemRegionVal(
+  getStateManager().getRegionManager().getCXXBaseObjectRegion(
+Base, Super, BaseSpec.isVirtual()));
+}
+
+inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass,
+   const SubRegion *Super,
+   bool isVirtual) const {
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+  BaseClass, Super, isVirtual));
+}
+
 inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
   return getStateManager().StoreMgr->getLValueVar(VD, LC);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46891: [StaticAnalyzer] Added a getLValue method to ProgramState for bases

2018-05-16 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 147045.
Szelethus added a comment.

Fixed a typo.


https://reviews.llvm.org/D46891

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h


Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -294,6 +294,13 @@
   ProgramStateRef enterStackFrame(const CallEvent &Call,
   const StackFrameContext *CalleeCtx) const;
 
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) 
const;
+
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
+bool IsVirtual) const;
+
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
 
@@ -724,6 +731,22 @@
   return this;
 }
 
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+   const SubRegion *Super) const {
+  const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+Base, Super, 
BaseSpec.isVirtual()));
+}
+
+inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass,
+   const SubRegion *Super,
+   bool IsVirtual) const {
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+  BaseClass, Super, 
IsVirtual));
+}
+
 inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
   return getStateManager().StoreMgr->getLValueVar(VD, LC);


Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -294,6 +294,13 @@
   ProgramStateRef enterStackFrame(const CallEvent &Call,
   const StackFrameContext *CalleeCtx) const;
 
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const;
+
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
+bool IsVirtual) const;
+
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
 
@@ -724,6 +731,22 @@
   return this;
 }
 
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+   const SubRegion *Super) const {
+  const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+Base, Super, BaseSpec.isVirtual()));
+}
+
+inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass,
+   const SubRegion *Super,
+   bool IsVirtual) const {
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+  BaseClass, Super, IsVirtual));
+}
+
 inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
   return getStateManager().StoreMgr->getLValueVar(VD, LC);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46891: [StaticAnalyzer] Added a getLValue method to ProgramState for bases

2018-05-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

Thanks for the review!

If you like the new overload, can you please commit this for me?


https://reviews.llvm.org/D46891



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45532: [StaticAnalyzer] Checker to find uninitialized fields after a constructor call

2018-05-18 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 147485.
Szelethus added a comment.

In this diff, I preferred placing `TODO`s in places where the logic of the 
checker would have changed too much. While I didn't have a strict rule for this 
in mind, I tried changing as little as possible in order to implement the fixes 
in smaller followup patches.

Now with that being said, I still did make numerous changes to address the 
inline comments, so here is a complete list of them:

- I placed the checker back in `alpha.cplusplus`
- While the main logic of the checker is unchanged, I did make some small 
additions: it turned out (thanks to @NoQ) that objects I wrongly referred to as 
fundamental were in fact of `BuiltinType` or `EnumeralType`. In the checker I 
defined these types as "primitive", as neither clang or the C++ standard 
defines a type called "primitive"
- A new node is added to the directed tree: objects of `MemberPointerType`. I 
updated the documentation, and added a function to `FindUninitializedFields` 
but left the implementation to be done in a followup patch
- String concatenations are all done with streams
- `FieldChainInfo` now uses `llvm::ImmutableList`
- `FieldChainInfo` is now completely immutable
- `FindUninitializedFields` no longer checks lazily, and has only a single 
`getUninitFields` public non-special member function.
- `FindUninitializedFields` now has a `ProgramStateRef` field instead of a 
bunch of managers (this added a dependency https://reviews.llvm.org/D46891)
- Added asserts and `llvm_unreachable` at numerous locations
- More comments for easier reading

For the test files:

- Changed all non-member function names to eliminate numbering
- Split `cxx-uninitialized-object.cpp` up, and placed pointer/reference tests 
in a different file
- Added tests for
  - `loc::ConcreteInt`
  - Member pointers
  - `BuiltinType` and `EnumeralType`
  - Constructorcall within a constructor, without the two constructors being in 
relation, to highlight a false negative
  - C++11 member initializers.

I'll be the first to admit that I'm not 100% sure I implemented the change to 
`llvm::ImmutableList` perfectly, so I guess maybe it's worth taking a deeper 
look at (but it certainly works!). Shall I tie its lifetime to the checker 
object's lifetime?
Of course, I rechecked the entire LLVM/Clang project and I'm happy to report 
that no crashes occured, and it emitted almost the same amount of warning 
(almost, because I used a newer version of clang).


https://reviews.llvm.org/D45532

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/Inputs/system-header-simulator-for-cxx-uninitialized-object.h
  test/Analysis/cxx-uninitialized-object-inheritance.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
  test/Analysis/cxx-uninitialized-object.cpp

Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- /dev/null
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -0,0 +1,1058 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -std=c++11 -DPEDANTIC -verify %s
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -std=c++11 -verify %s
+
+//===--===//
+// Default constructor test.
+//===--===//
+
+class CompilerGeneratedConstructorTest {
+  int a, b, c, d, e, f, g, h, i, j;
+
+public:
+  CompilerGeneratedConstructorTest() = default;
+};
+
+void fCompilerGeneratedConstructorTest() {
+  CompilerGeneratedConstructorTest();
+}
+
+#ifdef PEDANTIC
+class DefaultConstructorTest {
+  int a; // expected-note{{uninitialized field 'this->a'}}
+
+public:
+  DefaultConstructorTest();
+};
+
+DefaultConstructorTest::DefaultConstructorTest() = default;
+
+void fDefaultConstructorTest() {
+  DefaultConstructorTest(); // expected-warning{{1 uninitialized field}}
+}
+#else
+class DefaultConstructorTest {
+  int a;
+
+public:
+  DefaultConstructorTest();
+};
+
+DefaultConstructorTest::DefaultConstructorTest() = default;
+
+void fDefaultConstructorTest() {
+  DefaultConstructorTest();
+}
+#endif // PEDANTIC
+
+//===--===//
+// Initializer list test.
+//===--===//
+
+class InitListTest1 {
+  int a;
+  int b;
+
+public:
+  InitListTest1()
+  : a(1),
+b(2) {
+// All good!
+  }
+};
+
+void fInitListTest1() {
+  InitListTest1();
+}
+
+class InitListTest2 {
+  int a;
+  int b; // expected-note{{uninitialized field 'this->b'}}
+
+public:
+  InitListTest2()
+  : a(3) {} // expected-warning{{1 uninitialized field}}
+};

[PATCH] D45532: [StaticAnalyzer] Checker to find uninitialized fields after a constructor call

2018-05-18 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus marked 28 inline comments as done.
Szelethus added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:181-182
+/// Returns whether FD can be (transitively) dereferenced to a void pointer 
type
+/// (void*, void**, ...). The type of the region behind a void pointer isn't
+/// known, and thus FD can not be analyzed.
+bool isVoidPointer(const FieldDecl *FD);

NoQ wrote:
> Type of an object pointed to by a void pointer is something that our 
> path-sensitive engine is sometimes able to provide. It is not uncommon that a 
> void pointer points to a concrete variable on the current path, and we may 
> know it in the analyzer. I'm not sure this sort of check is necessary (i.e. 
> require more information).
> 
> You may also want to have a look at `getDynamicTypeInfo()` which is sometimes 
> capable of retrieving the dynamic type of the object pointed to by a pointer 
> or a reference - i.e. even if it's different from the pointee type of the 
> pointer.
I took a look at it, but I found that it'd change the implementation of 
`isPointerOrReferenceUninit` so much, I'd be a lot more comfortable if I could 
implement it in a smaller followup patch. I placed some `TODO`s in the code 
about this.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:223-225
+  ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState());
+  if (!Node)
+return;

NoQ wrote:
> I suspect that a fatal error is better here. We don't want the user to 
> receive duplicate report from other checkers that catch uninitialized values; 
> just one report is enough.
I think that would be a bad idea. For example, this checker shouts so loudly 
while checking the LLVM project, it would practically halt the analysis of the 
code, reducing the coverage, which means that checkers other then uninit value 
checkers would "suffer" from it.

However, I also think that having multiple uninit reports for the same object 
might be good, especially with this checker, as it would be very easy to see 
where the problem originated from.

What do you think?



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:405-406
+  SVal DerefdV = StoreMgr.getBinding(S, V.castAs());
+  while (Optional L = DerefdV.getAs())
+DerefdV = StoreMgr.getBinding(S, *L);
+

NoQ wrote:
> Is this loop guaranteed to terminate? Is something like `void *v; v = &v;` 
> possible?
> 
> I think this loop should unwrap the AST type on every iteration and 
> dereference the pointer accordingly.
> 
> In general, i believe that every symbolic pointer dereference should be made 
> with awareness of the type of the object we're trying to retrieve. Which is 
> an optional argument for `State->getSVal(R, ...)`, but it seems that it 
> should be made mandatory because in a lot of cases omitting it causes 
> problems.
> Is this loop guaranteed to terminate? Is something like void *v; v = &v; 
> possible?
I looked this up, and I am confident that it is not possible for a pointer to 
point to itself. Only a `void**` object may point to a `void*`. The loop 
terminates even if you do something evil like `v = 
reinterpret_cast(&v);` (I have tried this with `int`s).

>I think this loop should unwrap the AST type on every iteration and 
>dereference the pointer accordingly.
>
>In general, i believe that every symbolic pointer dereference should be made 
>with awareness of the type of the object we're trying to retrieve. Which is an 
>optional argument for State->getSVal(R, ...), but it seems that it should be 
>made mandatory because in a lot of cases omitting it causes problems.

I invested some serious effort into `getDynamicType`, but I think it'll require 
more time and some serious refactoring of this (`isPointerOrReferenceUninit`) 
function, so I'd post it separately.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:432
+  if (isUnionUninit(R)) {
+LocalChain.dereference();
+return addFieldToUninits(std::move(LocalChain));

NoQ wrote:
> Needs a comment on why the `IsDereferenced` flag on this path.
Added a comment at the line where I dereference the field that after that point 
we'll check the pointee.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:559-560
+  while (LC) {
+if (isa(LC->getDecl()))
+  return true;
+

NoQ wrote:
> This doesn't check that the constructor on the parent stack frame is anyhow 
> related to the current constructor, so it may introduce false negatives. For 
> instance, a class may lazy-initialize a singleton but never store a reference 
> to it within itself (because, well, it's a singleton, you can always obtain 
> the reference to it). In this case we'll never find the bug in the 
> constructor of the singleton.
Added a TODO and a test c

[PATCH] D46933: [analyzer] Added template argument lists to the Pathdiagnostic output

2018-05-25 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC333275: [analyzer] Added template argument lists to the 
Pathdiagnostic output (authored by Szelethus, committed by ).
Herald added a subscriber: cfe-commits.

Repository:
  rC Clang

https://reviews.llvm.org/D46933

Files:
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  test/Analysis/plist-diagnostics-template-function.cpp
  test/Analysis/plist-diagnostics-template-record.cpp

Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp
===
--- lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/OperationKinds.h"
@@ -1000,11 +1001,49 @@
 CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());
 }
 
+static void describeTemplateParameters(raw_ostream &Out,
+   const ArrayRef TAList,
+   const LangOptions &LO,
+   StringRef Prefix = StringRef(),
+   StringRef Postfix = StringRef());
+
+static void describeTemplateParameter(raw_ostream &Out,
+  const TemplateArgument &TArg,
+  const LangOptions &LO) {
+
+  if (TArg.getKind() == TemplateArgument::ArgKind::Pack) {
+describeTemplateParameters(Out, TArg.getPackAsArray(), LO);
+  } else {
+TArg.print(PrintingPolicy(LO), Out);
+  }
+}
+
+static void describeTemplateParameters(raw_ostream &Out,
+   const ArrayRef TAList,
+   const LangOptions &LO,
+   StringRef Prefix, StringRef Postfix) {
+  if (TAList.empty())
+return;
+
+  Out << Prefix;
+  for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) {
+describeTemplateParameter(Out, TAList[I], LO);
+Out << ", ";
+  }
+  describeTemplateParameter(Out, TAList[TAList.size() - 1], LO);
+  Out << Postfix;
+}
+
 static void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
   StringRef Prefix = StringRef()) {
   if (!D->getIdentifier())
 return;
-  Out << Prefix << '\'' << *D << '\'';
+  Out << Prefix << '\'' << *D;
+  if (const auto T = dyn_cast(D))
+describeTemplateParameters(Out, T->getTemplateArgs().asArray(),
+   D->getASTContext().getLangOpts(), "<", ">");
+
+  Out << '\'';
 }
 
 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
@@ -1062,7 +1101,16 @@
 return true;
   }
 
-  Out << Prefix << '\'' << cast(*D) << '\'';
+  Out << Prefix << '\'' << cast(*D);
+
+  // Adding template parameters.
+  if (const auto FD = dyn_cast(D))
+if (const TemplateArgumentList *TAList =
+FD->getTemplateSpecializationArgs())
+  describeTemplateParameters(Out, TAList->asArray(),
+ FD->getASTContext().getLangOpts(), "<", ">");
+
+  Out << '\'';
   return true;
 }
 
Index: test/Analysis/plist-diagnostics-template-function.cpp
===
--- test/Analysis/plist-diagnostics-template-function.cpp
+++ test/Analysis/plist-diagnostics-template-function.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_analyze_cc1 -analyzer-output=plist -o %t.plist -std=c++11 -analyzer-checker=core %s
+// RUN: FileCheck --input-file=%t.plist %s
+
+bool ret();
+
+template 
+void f(int i) {
+  if (ret())
+i = i / (i - 5);
+}
+
+template <>
+void f(int i) {
+  if (ret())
+i = i / (i - 5);
+}
+
+template 
+void defaultTemplateParameterFunction(int i) {
+  if (ret())
+int a = 10 / i;
+}
+
+template 
+void variadicTemplateFunction(int i) {
+  if (ret())
+int a = 10 / i;
+}
+
+int main() {
+  f(5);
+  f(5);
+  defaultTemplateParameterFunction<>(0);
+  variadicTemplateFunction(0);
+}
+
+// CHECK:  Calling 'f'
+// CHECK:  Calling 'f'
+// CHECK:  Calling 'defaultTemplateParameterFunction<0>'
+// CHECK:  Calling 'variadicTemplateFunction'
+
Index: test/Analysis/plist-diagnostics-template-record.cpp
===
--- test/Analysis/plist-diagnostics-template-record.cpp
+++ test/Analysis/plist-diagnostics-template-record.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_analyze_cc1 -analyzer-output=plist -o %t.plist -std=c++11 -analyzer-checker=core %s
+// RUN: FileCheck --input-file=%t.plist %s
+
+bool ret();
+
+template 
+struct DivByZero {
+  int i;
+  DivByZero(bool b) {
+if (ret())
+  i = 50 / (b - 1);
+  }
+};
+
+template 
+struct DivByZero {
+  int i;
+  DivByZero(bool b) {
+if (ret())
+

[PATCH] D46891: [StaticAnalyzer] Added a getLValue method to ProgramState for bases

2018-05-25 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC333278: [analyzer] Added a getLValue method to ProgramState 
for bases (authored by Szelethus, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D46891

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h


Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -294,6 +294,13 @@
   ProgramStateRef enterStackFrame(const CallEvent &Call,
   const StackFrameContext *CalleeCtx) const;
 
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) 
const;
+
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
+bool IsVirtual) const;
+
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
 
@@ -724,6 +731,22 @@
   return this;
 }
 
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+   const SubRegion *Super) const {
+  const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+Base, Super, 
BaseSpec.isVirtual()));
+}
+
+inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass,
+   const SubRegion *Super,
+   bool IsVirtual) const {
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+  BaseClass, Super, 
IsVirtual));
+}
+
 inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
   return getStateManager().StoreMgr->getLValueVar(VD, LC);


Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -294,6 +294,13 @@
   ProgramStateRef enterStackFrame(const CallEvent &Call,
   const StackFrameContext *CalleeCtx) const;
 
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const;
+
+  /// Get the lvalue for a base class object reference.
+  Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
+bool IsVirtual) const;
+
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
 
@@ -724,6 +731,22 @@
   return this;
 }
 
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+   const SubRegion *Super) const {
+  const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+Base, Super, BaseSpec.isVirtual()));
+}
+
+inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass,
+   const SubRegion *Super,
+   bool IsVirtual) const {
+  return loc::MemRegionVal(
+   getStateManager().getRegionManager().getCXXBaseObjectRegion(
+  BaseClass, Super, IsVirtual));
+}
+
 inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
   return getStateManager().StoreMgr->getLValueVar(VD, LC);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D45532: [StaticAnalyzer] Checker to find uninitialized fields after a constructor call

2018-05-27 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus marked 9 inline comments as done.
Szelethus added a comment.

Thanks again for taking a look :)




Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:359-372
+  // Checking bases.
+  const auto *CXXRD = dyn_cast(RD);
+  if (!CXXRD)
+return ContainsUninitField;
+
+  for (const CXXBaseSpecifier BaseSpec : CXXRD->bases()) {
+const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();

NoQ wrote:
> Szelethus wrote:
> > NoQ wrote:
> > > Are there many warnings that will be caused by this but won't be caused 
> > > by conducting the check for the constructor-within-constructor that's 
> > > currently disabled? Not sure - is it even syntactically possible to not 
> > > initialize the base class?
> > I'm not a 100% sure what you mean. Can you clarify?
> > >Not sure - is it even syntactically possible to not initialize the base 
> > >class?
> > If I understand the question correctly, no, as far as I know.
> You have a check for `isCalledByConstructor()` in order to skip base class 
> constructors but then you check them manually. That's a lot of code, but it 
> seems that the same result could have been achieved by simply skipping the 
> descent into the base class.
> 
> Same question for class-type fields, actually.
>Same question for class-type fields, actually.

My problem with that approach is that the same uninitialized field could've 
been emitted multiple times in different warnings. From an earlier conversation 
(assume that its run in pedantic mode):

>For this code snippet:
>
> ```
>struct A {
>   struct B {
>  int x, y;
>  
>  B() {}
>   } b;
>   int w;
>
>   A() {
>  b = B();
>   }
>};
>```
>the warning message after a call to `A::A()` would be "3 uninitialized 
>fields[...]", and for `B::B()` inside `A`s constructor would be "2 
>uninitialized fields[...]", so it wouldn't be filtered out.

In my opinion, if `A` contains a field of type `B`, it should be the 
responsibility of `A`'s constructors to initialize those fields properly.
>You have a check for isCalledByConstructor() in order to skip base class 
>constructors but then you check them manually. That's a lot of code, but it 
>seems that the same result could have been achieved by simply skipping the 
>descent into the base class.
I also believe that a constructor "should be held responsible" for the 
initialization of the inherited data members. However, in the case of base 
classes, uniqueing isn't an issue, as in this case:
```
struct B {
  int a;
  B() {}
};

struct D : public B {
  int b;
  D() {}
};
```
a call to `D::D()` would not check the inherited member (`a`), if I didn't 
implement it explicitly. That also means that if `isCalledByConstructor` was 
refactored to not filter out base classes, we would get two warning each with a 
single note, reporting `b` and `a` respectively. (I haven't actually checked 
it, but its a reasonable assumption)

Actually, I'm not 100% sure which approach is better: a warning for each base, 
or one warning for the object, bases included. I personally think one warning 
per object results in the best user experience.

I like both ideas, but I think if we'd come to the conclusion that a warning 
per base should be the way to go, it should definitely be implemented in a 
followup patch, as `isCalledByConstructor` is already in line for some major 
refactoring.

What do you think? :)



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:405-406
+  SVal DerefdV = StoreMgr.getBinding(S, V.castAs());
+  while (Optional L = DerefdV.getAs())
+DerefdV = StoreMgr.getBinding(S, *L);
+

NoQ wrote:
> Szelethus wrote:
> > NoQ wrote:
> > > Is this loop guaranteed to terminate? Is something like `void *v; v = 
> > > &v;` possible?
> > > 
> > > I think this loop should unwrap the AST type on every iteration and 
> > > dereference the pointer accordingly.
> > > 
> > > In general, i believe that every symbolic pointer dereference should be 
> > > made with awareness of the type of the object we're trying to retrieve. 
> > > Which is an optional argument for `State->getSVal(R, ...)`, but it seems 
> > > that it should be made mandatory because in a lot of cases omitting it 
> > > causes problems.
> > > Is this loop guaranteed to terminate? Is something like void *v; v = &v; 
> > > possible?
> > I looked this up, and I am confident that it is not possible for a pointer 
> > to point to itself. Only a `void**` object may point to a `void*`. The loop 
> > terminates even if you do something evil like `v = 
> > reinterpret_cast(&v);` (I have tried this with `int`s).
> > 
> > >I think this loop should unwrap the AST type on every iteration and 
> > >dereference the pointer accordingly.
> > >
> > >In general, i believe that every symbolic pointer dereference should be 
> > >made with awareness of the type of the object we're trying to retrieve. 
> > >Which is an optional argument for State->g

[PATCH] D45532: [StaticAnalyzer] Checker to find uninitialized fields after a constructor call

2018-05-28 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus marked 4 inline comments as done.
Szelethus added a comment.

I decided to mark the inline comments in `isPointerOrReferenceUninit` regarding 
the dereferencing loop termination done for now. I left several TODO's in the 
function to be fixed later, with many of them depending on one another, so 
fixing them all or many at once would probably be the best solution.

I left two conversations "not done" (fatal/nonfatal errors and base classes), 
but if I may, do you have any other objections?




Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:223-225
+  ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState());
+  if (!Node)
+return;

NoQ wrote:
> Szelethus wrote:
> > NoQ wrote:
> > > I suspect that a fatal error is better here. We don't want the user to 
> > > receive duplicate report from other checkers that catch uninitialized 
> > > values; just one report is enough.
> > I think that would be a bad idea. For example, this checker shouts so 
> > loudly while checking the LLVM project, it would practically halt the 
> > analysis of the code, reducing the coverage, which means that checkers 
> > other then uninit value checkers would "suffer" from it.
> > 
> > However, I also think that having multiple uninit reports for the same 
> > object might be good, especially with this checker, as it would be very 
> > easy to see where the problem originated from.
> > 
> > What do you think?
> Well, i guess that's the reason to not use the checker on LLVM. Regardless of 
> fatal/nonfatal warnings, enabling this checker on LLVM regularly would be a 
> bad idea because it's unlikely that anybody will be able to fix all the false 
> positives to make it usable. And for other projects that don't demonstrate 
> many false positives, this shouldn't be a problem.
> 
> In order to indicate where the problem originates from, we have our bug 
> reporter visitors that try their best to add such info directly to the 
> report. In particular, @george.karpenkov's recent `NoStoreFuncVisitor` 
> highlights functions in which a variable was //not// initialized but was 
> probably expected to be. Not sure if it highlights constructors in its 
> current shape, but that's definitely a better way to give this piece of 
> information to the user because it doesn't make the user look for a different 
> report to understand the current report.
LLVM is a special project in the fact that almost every part of it is so 
performance critical, that leaving many fields uninit matters. However, I would 
believe that in most projects, only a smaller portion of the code would be like 
that.

Suppose that we have a project that also defines a set of ADTs, like an 
`std::list`-like container. If that container had a field that would be left 
uninit after a ctor call, analysis on every execution path would be halted 
which would use an object like that.

My point is, as long as there is no way to tell the analyzer (or the checker) 
to ignore certain constructor calls, I think it would be best not to generate a 
fatal error.

>Regardless of fatal/nonfatal warnings, enabling this checker on LLVM regularly 
>would be a bad idea because it's unlikely that anybody will be able to fix all 
>the false positives to make it usable. And for other projects that don't 
>demonstrate many false positives, this shouldn't be a problem.
I wouldn't necessarily call them false positives. This checker doesn't look for 
bugs, and all reports I checked were correct in the fact that those fields 
really were left uninit. They just don't cause any trouble (just yet!).



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:359-372
+  // Checking bases.
+  const auto *CXXRD = dyn_cast(RD);
+  if (!CXXRD)
+return ContainsUninitField;
+
+  for (const CXXBaseSpecifier BaseSpec : CXXRD->bases()) {
+const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();

Szelethus wrote:
> NoQ wrote:
> > Szelethus wrote:
> > > NoQ wrote:
> > > > Are there many warnings that will be caused by this but won't be caused 
> > > > by conducting the check for the constructor-within-constructor that's 
> > > > currently disabled? Not sure - is it even syntactically possible to not 
> > > > initialize the base class?
> > > I'm not a 100% sure what you mean. Can you clarify?
> > > >Not sure - is it even syntactically possible to not initialize the base 
> > > >class?
> > > If I understand the question correctly, no, as far as I know.
> > You have a check for `isCalledByConstructor()` in order to skip base class 
> > constructors but then you check them manually. That's a lot of code, but it 
> > seems that the same result could have been achieved by simply skipping the 
> > descent into the base class.
> > 
> > Same question for class-type fields, actually.
> >Same question for class-type fields, actually.
> 
> My problem with that approach is that the same un

[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-08-23 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 162198.
Szelethus added a comment.

Addressed the inline comments.

- Added a `llvm::SmallSet` to further ensure the termination of the loop.
- Changed `isLocType` to `isDereferencableType`, block pointers are regarded as 
primitive objects.
- Added new tests


https://reviews.llvm.org/D51057

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
  test/Analysis/objcpp-uninitialized-object.mm

Index: test/Analysis/objcpp-uninitialized-object.mm
===
--- test/Analysis/objcpp-uninitialized-object.mm
+++ test/Analysis/objcpp-uninitialized-object.mm
@@ -4,7 +4,7 @@
 
 struct StructWithBlock {
   int a;
-  myBlock z; // expected-note{{uninitialized pointer 'this->z'}}
+  myBlock z; // expected-note{{uninitialized field 'this->z'}}
 
   StructWithBlock() : a(0), z(^{}) {}
 
Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -46,6 +46,50 @@
 }
 
 //===--===//
+// Alloca tests.
+//===--===//
+
+struct UntypedAllocaTest {
+  void *allocaPtr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  UntypedAllocaTest() : allocaPtr(__builtin_alloca(sizeof(int))) {
+// All good!
+  }
+};
+
+void fUntypedAllocaTest() {
+  UntypedAllocaTest();
+}
+
+struct TypedAllocaTest1 {
+  int *allocaPtr; // expected-note{{uninitialized pointee 'this->allocaPtr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  TypedAllocaTest1() // expected-warning{{1 uninitialized field}}
+  : allocaPtr(static_cast(__builtin_alloca(sizeof(int {}
+};
+
+void fTypedAllocaTest1() {
+  TypedAllocaTest1();
+}
+
+struct TypedAllocaTest2 {
+  int *allocaPtr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  TypedAllocaTest2()
+  : allocaPtr(static_cast(__builtin_alloca(sizeof(int {
+*allocaPtr = 5;
+// All good!
+  }
+};
+
+void fTypedAllocaTest2() {
+  TypedAllocaTest2();
+}
+
+//===--===//
 // Heap pointer tests.
 //===--===//
 
@@ -203,18 +247,14 @@
   CyclicPointerTest1();
 }
 
-// TODO: Currently, the checker ends up in an infinite loop for the following
-// test case.
-/*
 struct CyclicPointerTest2 {
-  int **pptr;
+  int **pptr; // no-crash
   CyclicPointerTest2() : pptr(reinterpret_cast(&pptr)) {}
 };
 
 void fCyclicPointerTest2() {
   CyclicPointerTest2();
 }
-*/
 
 //===--===//
 // Void pointer tests.
@@ -645,6 +685,15 @@
   CyclicList(&n1, int());
 }
 
+struct RingListTest {
+  RingListTest *next; // no-crash
+  RingListTest() : next(this) {}
+};
+
+void fRingListTest() {
+  RingListTest();
+}
+
 //===--===//
 // Tests for classes containing references.
 //===--===//
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -95,11 +95,13 @@
 /// known, and thus FD can not be analyzed.
 static bool isVoidPointer(QualType T);
 
-/// Dereferences \p V and returns the value and dynamic type of the pointee, as
-/// well as wether \p FR needs to be casted back to that type. If for whatever
-/// reason dereferencing fails, returns with None.
-static llvm::Optional>
-dereference(ProgramStateRef State, const FieldRegion *FR);
+using DereferenceInfo = std::pair;
+
+/// Dereferences \p FR and returns with the pointee's region, and whether it
+/// needs to be casted back to it's location type. If for whatever reason
+/// dereferencing fails, returns with None.
+static llvm::Optional dereference(ProgramStateRef State,
+   const FieldRegion *FR);
 
 //===--===//
 //   Methods for FindUninitializedFields.
@@ -110,10 +112,8 @@
 bool FindUninitializedFields::isPointerOrReferenceUninit(
 const FieldRegion *FR, FieldChainInfo LocalChain) {
 
-  assert((FR->getDecl()->getType()->isAnyPointerType() ||
-  FR->getDecl()->getType()->isReferenceType() ||
-  FR->getDecl

[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-08-23 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus marked 5 inline comments as done.
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h:259
+  return T->isBuiltinType() || T->isEnumeralType() ||
+ T->isMemberPointerType() || T->isBlockPointerType();
+}

I'm not sure this is correct -- do block pointers belong here? Since their 
region is not `TypedValueRegion`, I though they better fit here.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h:261-265
+inline bool isLocType(const QualType &T) {
+  return T->isAnyPointerType() || T->isReferenceType() ||
+ T->isBlockPointerType();
+}
+

NoQ wrote:
> We have a fancy static `Loc::isLocType()`.
Oh, good to know! However, it also returns true for `nullptr_t`, which also 
happens to be a `BuiltinType`. I'd like to keep `isPrimitiveType` and (the now 
renamed) `isDereferencableType` categories disjunctive. Primitive types require 
no further analysis other then checking whether they are initialized or not, 
which is true for `nullptr_t` objects.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp:240-244
+if (Tmp->getRegion()->getSymbolicBase())
   return None;
-}
 
-V = State->getSVal(*Tmp, DynT);
+DynT = DynT->getPointeeType();
+R = Tmp->getRegionAs();

NoQ wrote:
> This code seems to be duplicated with the "0th iteration" before the loop. I 
> guess you can put everything into the loop.
I moved some code into the loop, but I think that I really need a 0th iteration 
to make the code readable.


https://reviews.llvm.org/D51057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-08-23 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 162205.
Szelethus added a comment.

Rebased to https://reviews.llvm.org/D51057.


https://reviews.llvm.org/D50892

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp


Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -781,21 +781,38 @@
 // Dynamic type test.
 
//===--===//
 
-struct DynTBase {};
-struct DynTDerived : DynTBase {
-  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
-  int x; // no-note
+struct DynTBase1 {};
+struct DynTDerived1 : DynTBase1 {
+  int y; // expected-note{{uninitialized field 'this->bptr->y'}}
 };
 
-struct DynamicTypeTest {
-  DynTBase *bptr;
+struct DynamicTypeTest1 {
+  DynTBase1 *bptr;
   int i = 0;
 
-  // TODO: we'd expect the warning: {{1 uninitialized field}}
-  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+  DynamicTypeTest1(DynTBase1 *bptr) : bptr(bptr) {} // expected-warning{{1 
uninitialized field}}
 };
 
-void f() {
-  DynTDerived d;
-  DynamicTypeTest t(&d);
+void fDynamicTypeTest1() {
+  DynTDerived1 d;
+  DynamicTypeTest1 t(&d);
 };
+
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'this->bptr->DynTBase2::x'}}
+};
+struct DynTDerived2 : DynTBase2 {
+  int y; // expected-note{{uninitialized field 'this->bptr->y'}}
+};
+
+struct DynamicTypeTest2 {
+  DynTBase2 *bptr;
+  int i = 0;
+
+  DynamicTypeTest2(DynTBase2 *bptr) : bptr(bptr) {} // expected-warning{{2 
uninitialized fields}}
+};
+
+void fDynamicTypeTest2() {
+  DynTDerived2 d;
+  DynamicTypeTest2 t(&d);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -240,5 +240,9 @@
   break;
   }
 
+  while (R->getAs()) {
+R = R->getSuperRegion()->getAs();
+  }
+
   return std::make_pair(R, NeedsCastBack);
 }


Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -781,21 +781,38 @@
 // Dynamic type test.
 //===--===//
 
-struct DynTBase {};
-struct DynTDerived : DynTBase {
-  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
-  int x; // no-note
+struct DynTBase1 {};
+struct DynTDerived1 : DynTBase1 {
+  int y; // expected-note{{uninitialized field 'this->bptr->y'}}
 };
 
-struct DynamicTypeTest {
-  DynTBase *bptr;
+struct DynamicTypeTest1 {
+  DynTBase1 *bptr;
   int i = 0;
 
-  // TODO: we'd expect the warning: {{1 uninitialized field}}
-  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+  DynamicTypeTest1(DynTBase1 *bptr) : bptr(bptr) {} // expected-warning{{1 uninitialized field}}
 };
 
-void f() {
-  DynTDerived d;
-  DynamicTypeTest t(&d);
+void fDynamicTypeTest1() {
+  DynTDerived1 d;
+  DynamicTypeTest1 t(&d);
 };
+
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'this->bptr->DynTBase2::x'}}
+};
+struct DynTDerived2 : DynTBase2 {
+  int y; // expected-note{{uninitialized field 'this->bptr->y'}}
+};
+
+struct DynamicTypeTest2 {
+  DynTBase2 *bptr;
+  int i = 0;
+
+  DynamicTypeTest2(DynTBase2 *bptr) : bptr(bptr) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fDynamicTypeTest2() {
+  DynTDerived2 d;
+  DynamicTypeTest2 t(&d);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -240,5 +240,9 @@
   break;
   }
 
+  while (R->getAs()) {
+R = R->getSuperRegion()->getAs();
+  }
+
   return std::make_pair(R, NeedsCastBack);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-08-23 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp:187-191
   // If FR is a pointer pointing to a non-primitive type.
   if (Optional RecordV =
   DerefdV.getAs()) {
 
 const TypedValueRegion *R = RecordV->getRegion();

NoQ wrote:
> Szelethus wrote:
> > NoQ wrote:
> > > This looks like one more situation where we dereference a location to get 
> > > a value and then struggle to get back to the location that we've 
> > > dereferenced by looking at the value. Can we just use `V`?
> > I've struggled with derefencing for months now -- I'm afraid I just don't 
> > really get what you'd like to see here.
> > 
> > Here's what I attempted to implement:
> > I'd like to obtain the pointee's region of a `Loc` region, even if it has 
> > to be casted to another type, like through void pointers and 
> > `nonloc::LocAsInteger`, and continue analysis on said region as usual.
> > 
> > The trickiest part I can't seem to get right is the acquisition of the 
> > pointee region. For the problem this patch attempts to solve, even though 
> > `DynT` correctly says that the dynamic type is `DynTDerived2 *`, `DerefdV` 
> > contains a region for `DynTBase`.
> > 
> > I uploaded a new patch, D51057, which hopefully settles derefence related 
> > issues. Please note that it **does not **replace this diff, as the acquired 
> > region is still of type `DynTBase`.
> > 
> > I find understanding these intricate details of the analyzer very 
> > difficult, as I found very little documentation about how this works, which 
> > often left me guessing what the proper way to do this is. Can you recommend 
> > some literature for me on this field?
> > Can you recommend some literature for me on this field?
> 
> This is pretty specific to our analyzer. `SVal`/`SymExpr`/`MemRegion` 
> hierarchy is tightly coupled to implementation details of the `RegionStore`, 
> which is our memory model. There's a paper on it [1]. We have some in-tree 
> documentation of the `RegionStore` [2] (other docs there are also interesting 
> to read). And there's my old workbook [3]. And i guess that's it.
> 
> [1] Xu, Zhongxing & Kremenek, Ted & Zhang, Jian. (2010). A Memory Model for 
> Static Analysis of C Programs. 535-548. 10.1007/978-3-642-16558-0_44.
> [2] 
> https://github.com/llvm-mirror/clang/blob/master/docs/analyzer/RegionStore.txt
> [3] 
> https://github.com/haoNoQ/clang-analyzer-guide/releases/download/v0.1/clang-analyzer-guide-v0.1.pdf
Thank you! I'm aware of these works, and have read them already.

The actual implementation of the analyzer is most described in your book, and 
I've often got the best ideas from that. However, some very well described 
things in there have absolutely no documentation in the actual code -- for 
example, it isn't obvious at all to me what `CompundValue` is, and I was 
surprised to learn what it does from your guide. Other examples are the 
difference between `TypedValueRegion`s `getLocationType` and `getValueType`, 
`SymExpr` in general, and so on.

I think it would also be very valuable to have a link in `docs/analyzer` to 
your book. On another note, would you mind if I were to put some of the 
information from there into the actual code?



Comment at: test/Analysis/cxx-uninitialized-object-inheritance.cpp:787
   // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
   int x; // no-note
 };

NoQ wrote:
> Szelethus wrote:
> > The checker should be able to catch this one -- for some reason it is 
> > regarded as an unknown region. Odd, as the test case right after this one 
> > works perfectly.
> There's a variety of problems we have with empty base classes, might be one 
> of those, and they are usually easy to fix because, well, yes it's a special 
> case, but it's also an extremely simple case.
> 
> I encourage you to open up the Exploded Graph and study it carefully to see 
> what and where goes wrong (not for this revision).
I'd love to learn about other parts of the analyzer (besides chasing pointers), 
but for now, this seems to have fixed itself ;)


https://reviews.llvm.org/D50892



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-08-27 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 162658.
Szelethus marked 5 inline comments as done.
Szelethus added a comment.

Actually, the note messages were incorrect as in this case the static and 
dynamic type of the object differs.


https://reviews.llvm.org/D50892

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp


Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -781,21 +781,38 @@
 // Dynamic type test.
 
//===--===//
 
-struct DynTBase {};
-struct DynTDerived : DynTBase {
-  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
-  int x; // no-note
+struct DynTBase1 {};
+struct DynTDerived1 : DynTBase1 {
+  int y; // expected-note{{uninitialized field 'static_cast(this->bptr)->y'}}
 };
 
-struct DynamicTypeTest {
-  DynTBase *bptr;
+struct DynamicTypeTest1 {
+  DynTBase1 *bptr;
   int i = 0;
 
-  // TODO: we'd expect the warning: {{1 uninitialized field}}
-  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+  DynamicTypeTest1(DynTBase1 *bptr) : bptr(bptr) {} // expected-warning{{1 
uninitialized field}}
 };
 
-void f() {
-  DynTDerived d;
-  DynamicTypeTest t(&d);
+void fDynamicTypeTest1() {
+  DynTDerived1 d;
+  DynamicTypeTest1 t(&d);
 };
+
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'static_cast(this->bptr)->DynTBase2::x'}}
+};
+struct DynTDerived2 : DynTBase2 {
+  int y; // expected-note{{uninitialized field 'static_cast(this->bptr)->y'}}
+};
+
+struct DynamicTypeTest2 {
+  DynTBase2 *bptr;
+  int i = 0;
+
+  DynamicTypeTest2(DynTBase2 *bptr) : bptr(bptr) {} // expected-warning{{2 
uninitialized fields}}
+};
+
+void fDynamicTypeTest2() {
+  DynTDerived2 d;
+  DynamicTypeTest2 t(&d);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -240,5 +240,10 @@
   break;
   }
 
+  while (R->getAs()) {
+NeedsCastBack = true;
+R = R->getSuperRegion()->getAs();
+  }
+
   return std::make_pair(R, NeedsCastBack);
 }


Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -781,21 +781,38 @@
 // Dynamic type test.
 //===--===//
 
-struct DynTBase {};
-struct DynTDerived : DynTBase {
-  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
-  int x; // no-note
+struct DynTBase1 {};
+struct DynTDerived1 : DynTBase1 {
+  int y; // expected-note{{uninitialized field 'static_cast(this->bptr)->y'}}
 };
 
-struct DynamicTypeTest {
-  DynTBase *bptr;
+struct DynamicTypeTest1 {
+  DynTBase1 *bptr;
   int i = 0;
 
-  // TODO: we'd expect the warning: {{1 uninitialized field}}
-  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+  DynamicTypeTest1(DynTBase1 *bptr) : bptr(bptr) {} // expected-warning{{1 uninitialized field}}
 };
 
-void f() {
-  DynTDerived d;
-  DynamicTypeTest t(&d);
+void fDynamicTypeTest1() {
+  DynTDerived1 d;
+  DynamicTypeTest1 t(&d);
 };
+
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'static_cast(this->bptr)->DynTBase2::x'}}
+};
+struct DynTDerived2 : DynTBase2 {
+  int y; // expected-note{{uninitialized field 'static_cast(this->bptr)->y'}}
+};
+
+struct DynamicTypeTest2 {
+  DynTBase2 *bptr;
+  int i = 0;
+
+  DynamicTypeTest2(DynTBase2 *bptr) : bptr(bptr) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fDynamicTypeTest2() {
+  DynTDerived2 d;
+  DynamicTypeTest2 t(&d);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -240,5 +240,10 @@
   break;
   }
 
+  while (R->getAs()) {
+NeedsCastBack = true;
+R = R->getSuperRegion()->getAs();
+  }
+
   return std::make_pair(R, NeedsCastBack);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51300: [analyzer][UninitializedObjectChecker] No longer using nonloc::LazyCompoundVal

2018-08-27 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: NoQ, george.karpenkov, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

As rightly pointed out by @NoQ, `nonloc::LazyCompoundVal`s were only used to 
acquire a constructed object's region, which isn't what `LazyCompoundVal` was 
made for.


Repository:
  rC Clang

https://reviews.llvm.org/D51300

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp


Index: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -124,12 +124,11 @@
 
 // Utility function declarations.
 
-/// Returns the object that was constructed by CtorDecl, or None if that isn't
-/// possible.
-// TODO: Refactor this function so that it returns the constructed object's
-// region.
-static Optional
-getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
+/// Returns the region that was constructed by CtorDecl, or nullptr if that
+/// isn't possible.
+static const TypedValueRegion *
+getConstructedRegion(const CXXConstructorDecl *CtorDecl,
+ CheckerContext &Context);
 
 /// Checks whether the object constructed by \p Ctor will be analyzed later
 /// (e.g. if the object is a field of another object, in which case we'd check
@@ -159,12 +158,11 @@
   if (willObjectBeAnalyzedLater(CtorDecl, Context))
 return;
 
-  Optional Object = getObjectVal(CtorDecl, Context);
-  if (!Object)
+  const TypedValueRegion *R = getConstructedRegion(CtorDecl, Context);
+  if (!R)
 return;
 
-  FindUninitializedFields F(Context.getState(), Object->getRegion(),
-CheckPointeeInitialization);
+  FindUninitializedFields F(Context.getState(), R, CheckPointeeInitialization);
 
   const UninitFieldMap &UninitFields = F.getUninitFields();
 
@@ -443,25 +441,23 @@
 //   Utility functions.
 
//===--===//
 
-static Optional
-getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context) {
+static const TypedValueRegion *
+getConstructedRegion(const CXXConstructorDecl *CtorDecl,
+ CheckerContext &Context) {
 
   Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl->getParent(),
 Context.getStackFrame());
-  // Getting the value for 'this'.
-  SVal This = Context.getState()->getSVal(ThisLoc);
 
-  // Getting the value for '*this'.
-  SVal Object = Context.getState()->getSVal(This.castAs());
+  SVal ObjectV = Context.getState()->getSVal(ThisLoc);
 
-  return Object.getAs();
+  return ObjectV.getAsRegion()->getAs();
 }
 
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
   CheckerContext &Context) {
 
-  Optional CurrentObject = getObjectVal(Ctor, 
Context);
-  if (!CurrentObject)
+  const TypedValueRegion *CurrRegion = getConstructedRegion(Ctor, Context);
+  if (!CurrRegion)
 return false;
 
   const LocationContext *LC = Context.getLocationContext();
@@ -472,14 +468,14 @@
 if (!OtherCtor)
   continue;
 
-Optional OtherObject =
-getObjectVal(OtherCtor, Context);
-if (!OtherObject)
+const TypedValueRegion *OtherRegion =
+getConstructedRegion(OtherCtor, Context);
+if (!OtherRegion)
   continue;
 
-// If the CurrentObject is a subregion of OtherObject, it will be analyzed
-// during the analysis of OtherObject.
-if (CurrentObject->getRegion()->isSubRegionOf(OtherObject->getRegion()))
+// If the CurrRegion is a subregion of OtherRegion, it will be analyzed
+// during the analysis of OtherRegion.
+if (CurrRegion->isSubRegionOf(OtherRegion))
   return true;
   }
 


Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -124,12 +124,11 @@
 
 // Utility function declarations.
 
-/// Returns the object that was constructed by CtorDecl, or None if that isn't
-/// possible.
-// TODO: Refactor this function so that it returns the constructed object's
-// region.
-static Optional
-getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
+/// Returns the region that was constructed by CtorDecl, or nullptr if that
+/// isn't possible.
+static const TypedValueRegion *
+getConstructedRegion(const CXXConstructorDecl *CtorDecl,
+ CheckerContext &Context);
 
 /// Checks whether the object constructed by

[PATCH] D49986: [ADT] ImmutableList::add parameters are switched

2018-08-28 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus abandoned this revision.
Szelethus added a comment.

In https://reviews.llvm.org/D49986#1192798, @Szelethus wrote:

> In https://reviews.llvm.org/D49985#1181568, @NoQ wrote:
>
> > In https://reviews.llvm.org/D49985#1181564, @dblaikie wrote:
> >
> > > It looks like concat orders the arguments in the same way that the output 
> > > would be (so concat(X, list) produces [X, list]) - so preserving that 
> > > argument order seems like it improves/retains readability compared to 
> > > switching them around so 'concat(list, X)' produces '[X, list]'.
> >
> >
> > Yeah, i guess that might have been the motivation behind such 
> > inconsistency. I'll be fine with fixing the order for other data structures.
>
>
> @NoQ Have your views changed about this patch? Shall I abandon it?


I've decided to do so after https://reviews.llvm.org/rL340824.


Repository:
  rC Clang

https://reviews.llvm.org/D49986



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-08-28 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: test/Analysis/cxx-uninitialized-object-inheritance.cpp:802
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'static_cast(this->bptr)->DynTBase2::x'}}
+};

NoQ wrote:
> Mmm, what's the value of casting to derived type and then specifying that we 
> access the field of the base type anyway? Isn't `this->bptr->x` exactly what 
> the user needs to know(?)
True, but it's a one tough job to write `this->bptr->x` here and also a correct 
note message for...



Comment at: test/Analysis/cxx-uninitialized-object-inheritance.cpp:805
+struct DynTDerived2 : DynTBase2 {
+  int y; // expected-note{{uninitialized field 'static_cast(this->bptr)->y'}}
+};

...this one. I'll see how I could achieve it without disrupting `FieldNode`'s 
interface too much.


https://reviews.llvm.org/D50892



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51300: [analyzer][UninitializedObjectChecker] No longer using nonloc::LazyCompoundVal

2018-08-29 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp:448-449
 
   Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl->getParent(),
 Context.getStackFrame());
 

NoQ wrote:
> This totally needs `assert(CtorDecl == Context.getStackFrame()->getDecl())`. 
> Otherwise we're in big trouble because we'll be looking into a this-region 
> that doesn't exist on this stack frame.
> 
> On second thought, though, i guess we should put this assertion into the 
> constructor of `CXXThisRegion`. I'll do this.
> 
> Also there's an overload of `getCXXThis` that accepts the method itself, no 
> need to get parent.
U that wouldn't be very nice, because...



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp:456-483
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
   CheckerContext &Context) {
 
-  Optional CurrentObject = getObjectVal(Ctor, 
Context);
-  if (!CurrentObject)
+  const TypedValueRegion *CurrRegion = getConstructedRegion(Ctor, Context);
+  if (!CurrRegion)
 return false;
 

...`willBeAnalyzerLater()` relies on this, and it uses all sorts of constructor 
decls to check whether `Context.getLocationContext()->getDecl()` would be a 
subregion of another object. Are you sure that this is incorrect?


Repository:
  rC Clang

https://reviews.llvm.org/D51300



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51417: [analyzer][UninitializedObjectChecker] Updated comments

2018-08-29 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: NoQ, george.karpenkov, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

Some of the comments are incorrect, imprecise, or simply nonexistent. Since I 
have a better grasp on how the analyzer works, it makes sense to update most of 
them in a single swoop.

I tried not to flood the code with comments too much, this amount feels just 
right to me.


Repository:
  rC Clang

https://reviews.llvm.org/D51417

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -1,4 +1,4 @@
-//===- UninitializedPointer.cpp --*- C++ -*-==//
+//===- UninitializedPointee.cpp --*- C++ -*-==//
 //
 // The LLVM Compiler Infrastructure
 //
@@ -90,9 +90,8 @@
 
 // Utility function declarations.
 
-/// Returns whether T can be (transitively) dereferenced to a void pointer type
-/// (void*, void**, ...). The type of the region behind a void pointer isn't
-/// known, and thus FD can not be analyzed.
+/// Returns whether \p T can be (transitively) dereferenced to a void pointer
+/// type (void*, void**, ...).
 static bool isVoidPointer(QualType T);
 
 using DereferenceInfo = std::pair;
@@ -107,9 +106,7 @@
 //   Methods for FindUninitializedFields.
 //===--===//
 
-// Note that pointers/references don't contain fields themselves, so in this
-// function we won't add anything to LocalChain.
-bool FindUninitializedFields::isPointerOrReferenceUninit(
+bool FindUninitializedFields::isDereferencableUninit(
 const FieldRegion *FR, FieldChainInfo LocalChain) {
 
   assert(isDereferencableType(FR->getDecl()->getType()) &&
@@ -224,12 +221,11 @@
   while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
 
 R = Tmp->getAs();
-
 if (!R)
   return None;
 
 // We found a cyclic pointer, like int *ptr = (int *)&ptr.
-// TODO: Report these fields too.
+// TODO: Should we report these fields too?
 if (!VisitedRegions.insert(R).second)
   return None;
 
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -94,7 +94,9 @@
 };
 
 /// Represents that the FieldNode that comes after this is declared in a base
-/// of the previous FieldNode.
+/// of the previous FieldNode. As such, this descendant doesn't wrap a
+/// FieldRegion, and is purely a tool to describe a relation between two other
+/// FieldRegion wrapping descendants.
 class BaseClass final : public FieldNode {
   const QualType BaseClassT;
 
@@ -291,7 +293,7 @@
 }
 
 if (isDereferencableType(T)) {
-  if (isPointerOrReferenceUninit(FR, LocalChain))
+  if (isDereferencableUninit(FR, LocalChain))
 ContainsUninitField = true;
   continue;
 }
@@ -309,7 +311,8 @@
 llvm_unreachable("All cases are handled!");
   }
 
-  // Checking bases.
+  // Checking bases. The checker will regard inherited data members as direct
+  // fields.
   const auto *CXXRD = dyn_cast(RD);
   if (!CXXRD)
 return ContainsUninitField;
@@ -356,6 +359,9 @@
 
 const FieldRegion *FieldChainInfo::getUninitRegion() const {
   assert(!Chain.isEmpty() && "Empty fieldchain!");
+
+  // ImmutableList::getHead() isn't a const method, hence the not too nice
+  // implementation.
   return (*Chain.begin()).getRegion();
 }
 
@@ -370,31 +376,11 @@
 /// Prints every element except the last to `Out`. Since ImmutableLists store
 /// elements in reverse order, and have no reverse iterators, we use a
 /// recursive function to print the fieldchain correctly. The last element in
-/// the chain is to be printed by `print`.
+/// the chain is to be printed by `FieldChainInfo::print`.
 static void printTail(llvm::raw_ostream &Out,
   const FieldChainInfo::FieldChainImpl *L);
 
-// TODO: This function constructs an incorrect string if a void pointer is a
-// part of the chain:
-//
-//   struct B { int x; }
-//
-//   struct A {
-// void *vptr;
-// A(void* vptr) : vptr(vptr) {}
-//   };
-//
-//   void f() {
-// B b;
-// A a(&b);
-//   }
-//
-// The note message will be "uninitialized field 'this->vptr->x'", even tho

[PATCH] D51417: [analyzer][UninitializedObjectChecker] Updated comments

2018-08-29 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp:377-397
-// TODO: This function constructs an incorrect string if a void pointer is a
-// part of the chain:
-//
-//   struct B { int x; }
-//
-//   struct A {
-// void *vptr;

Fixed in rC339653, but apparently I forgot to remove this.


Repository:
  rC Clang

https://reviews.llvm.org/D51417



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-08-29 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: test/Analysis/cxx-uninitialized-object-inheritance.cpp:802
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'static_cast(this->bptr)->DynTBase2::x'}}
+};

NoQ wrote:
> Szelethus wrote:
> > NoQ wrote:
> > > Mmm, what's the value of casting to derived type and then specifying that 
> > > we access the field of the base type anyway? Isn't `this->bptr->x` 
> > > exactly what the user needs to know(?)
> > True, but it's a one tough job to write `this->bptr->x` here and also a 
> > correct note message for...
> I guess don't try too hard, eg. say if it requires something of non-linear 
> complexity it's probably not worth it (not because it'd be slow but because 
> it'd be an indication that it might be not worth the effort).
I actually invested some effort into this and I'm fairly certain I could pull 
it off with O(n) complexity, but I'll probably just place a TODO in the code 
for now, as I have other things I really want to get fixed first.


https://reviews.llvm.org/D50892



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-08-29 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

I managed to cause a bunch of crashes with this patch, so consider it as a work 
in progress for now :/


https://reviews.llvm.org/D51057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-08-29 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 163185.
Szelethus added a comment.

Fixed two crashes. Interesting how many much better this approach works, as 
I've never encountered `FunctionType`d objects or only forward declared typed 
pointers after dereferencing.


https://reviews.llvm.org/D51057

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
  test/Analysis/objcpp-uninitialized-object.mm

Index: test/Analysis/objcpp-uninitialized-object.mm
===
--- test/Analysis/objcpp-uninitialized-object.mm
+++ test/Analysis/objcpp-uninitialized-object.mm
@@ -4,7 +4,7 @@
 
 struct StructWithBlock {
   int a;
-  myBlock z; // expected-note{{uninitialized pointer 'this->z'}}
+  myBlock z; // expected-note{{uninitialized field 'this->z'}}
 
   StructWithBlock() : a(0), z(^{}) {}
 
Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -46,6 +46,50 @@
 }
 
 //===--===//
+// Alloca tests.
+//===--===//
+
+struct UntypedAllocaTest {
+  void *allocaPtr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  UntypedAllocaTest() : allocaPtr(__builtin_alloca(sizeof(int))) {
+// All good!
+  }
+};
+
+void fUntypedAllocaTest() {
+  UntypedAllocaTest();
+}
+
+struct TypedAllocaTest1 {
+  int *allocaPtr; // expected-note{{uninitialized pointee 'this->allocaPtr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  TypedAllocaTest1() // expected-warning{{1 uninitialized field}}
+  : allocaPtr(static_cast(__builtin_alloca(sizeof(int {}
+};
+
+void fTypedAllocaTest1() {
+  TypedAllocaTest1();
+}
+
+struct TypedAllocaTest2 {
+  int *allocaPtr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  TypedAllocaTest2()
+  : allocaPtr(static_cast(__builtin_alloca(sizeof(int {
+*allocaPtr = 5;
+// All good!
+  }
+};
+
+void fTypedAllocaTest2() {
+  TypedAllocaTest2();
+}
+
+//===--===//
 // Heap pointer tests.
 //===--===//
 
@@ -203,18 +247,14 @@
   CyclicPointerTest1();
 }
 
-// TODO: Currently, the checker ends up in an infinite loop for the following
-// test case.
-/*
 struct CyclicPointerTest2 {
-  int **pptr;
+  int **pptr; // no-crash
   CyclicPointerTest2() : pptr(reinterpret_cast(&pptr)) {}
 };
 
 void fCyclicPointerTest2() {
   CyclicPointerTest2();
 }
-*/
 
 //===--===//
 // Void pointer tests.
@@ -471,6 +511,39 @@
 }
 
 //===--===//
+// Incomplete pointee tests.
+//===--===//
+
+class IncompleteType;
+
+struct IncompletePointeeTypeTest {
+  IncompleteType *pImpl; //no-crash
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IncompletePointeeTypeTest(IncompleteType *A) : pImpl(A) {}
+};
+
+void fIncompletePointeeTypeTest(void *ptr) {
+  IncompletePointeeTypeTest(reinterpret_cast(ptr));
+}
+
+//===--===//
+// Function pointer tests.
+//===--===//
+
+struct FunctionPointerWithDifferentDynTypeTest {
+  using Func1 = void *(*)();
+  using Func2 = int *(*)();
+
+  Func1 f; // no-crash
+  FunctionPointerWithDifferentDynTypeTest(Func2 f) : f((Func1)f) {}
+};
+
+// Note that there isn't a function calling the constructor of
+// FunctionPointerWithDifferentDynTypeTest, because a crash could only be
+// reproduced without it.
+
+//===--===//
 // Member pointer tests.
 //===--===//
 
@@ -645,6 +718,15 @@
   CyclicList(&n1, int());
 }
 
+struct RingListTest {
+  RingListTest *next; // no-crash
+  RingListTest() : next(this) {}
+};
+
+void fRingListTest() {
+  RingListTest();
+}
+
 //===--===//
 // Tests for classes containing references.
 //===--===//
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib

[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-08-31 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 163479.
Szelethus added a comment.

Fixed a crash, where the super region was symbolic.

In https://reviews.llvm.org/D50892#1218060, @NoQ wrote:

> Let's commit then?


I'd be much more comfortable landing https://reviews.llvm.org/D51057 before 
modifying dereferencing any further.


https://reviews.llvm.org/D50892

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp


Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -781,21 +781,53 @@
 // Dynamic type test.
 
//===--===//
 
-struct DynTBase {};
-struct DynTDerived : DynTBase {
-  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
-  int x; // no-note
+struct DynTBase1 {};
+struct DynTDerived1 : DynTBase1 {
+  int y; // expected-note{{uninitialized field 'static_cast(this->bptr)->y'}}
 };
 
-struct DynamicTypeTest {
-  DynTBase *bptr;
+struct DynamicTypeTest1 {
+  DynTBase1 *bptr;
   int i = 0;
 
-  // TODO: we'd expect the warning: {{1 uninitialized field}}
-  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+  DynamicTypeTest1(DynTBase1 *bptr) : bptr(bptr) {} // expected-warning{{1 
uninitialized field}}
 };
 
-void f() {
-  DynTDerived d;
-  DynamicTypeTest t(&d);
+void fDynamicTypeTest1() {
+  DynTDerived1 d;
+  DynamicTypeTest1 t(&d);
 };
+
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'static_cast(this->bptr)->DynTBase2::x'}}
+};
+struct DynTDerived2 : DynTBase2 {
+  int y; // expected-note{{uninitialized field 'static_cast(this->bptr)->y'}}
+};
+
+struct DynamicTypeTest2 {
+  DynTBase2 *bptr;
+  int i = 0;
+
+  DynamicTypeTest2(DynTBase2 *bptr) : bptr(bptr) {} // expected-warning{{2 
uninitialized fields}}
+};
+
+void fDynamicTypeTest2() {
+  DynTDerived2 d;
+  DynamicTypeTest2 t(&d);
+}
+
+struct SymbolicSuperRegionBase {
+  SymbolicSuperRegionBase() {}
+};
+
+struct SymbolicSuperRegionDerived : SymbolicSuperRegionBase {
+  SymbolicSuperRegionBase *bptr; // no-crash
+  SymbolicSuperRegionDerived(SymbolicSuperRegionBase *bptr) : bptr(bptr) {}
+};
+
+SymbolicSuperRegionDerived *getSymbolicRegion();
+
+void fSymbolicSuperRegionTest() {
+  SymbolicSuperRegionDerived test(getSymbolicRegion());
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -240,5 +240,13 @@
   break;
   }
 
+  while (R->getAs()) {
+NeedsCastBack = true;
+
+if (!isa(R->getSuperRegion()))
+  break;
+R = R->getSuperRegion()->getAs();
+  }
+
   return std::make_pair(R, NeedsCastBack);
 }


Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -781,21 +781,53 @@
 // Dynamic type test.
 //===--===//
 
-struct DynTBase {};
-struct DynTDerived : DynTBase {
-  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
-  int x; // no-note
+struct DynTBase1 {};
+struct DynTDerived1 : DynTBase1 {
+  int y; // expected-note{{uninitialized field 'static_cast(this->bptr)->y'}}
 };
 
-struct DynamicTypeTest {
-  DynTBase *bptr;
+struct DynamicTypeTest1 {
+  DynTBase1 *bptr;
   int i = 0;
 
-  // TODO: we'd expect the warning: {{1 uninitialized field}}
-  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+  DynamicTypeTest1(DynTBase1 *bptr) : bptr(bptr) {} // expected-warning{{1 uninitialized field}}
 };
 
-void f() {
-  DynTDerived d;
-  DynamicTypeTest t(&d);
+void fDynamicTypeTest1() {
+  DynTDerived1 d;
+  DynamicTypeTest1 t(&d);
 };
+
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'static_cast(this->bptr)->DynTBase2::x'}}
+};
+struct DynTDerived2 : DynTBase2 {
+  int y; // expected-note{{uninitialized field 'static_cast(this->bptr)->y'}}
+};
+
+struct DynamicTypeTest2 {
+  DynTBase2 *bptr;
+  int i = 0;
+
+  DynamicTypeTest2(DynTBase2 *bptr) : bptr(bptr) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fDynamicTypeTest2() {
+  DynTDerived2 d;
+  DynamicTypeTest2 t(&d);
+}
+
+struct SymbolicSuperRegionBase {
+  SymbolicSuperRegionBase() {}
+};
+
+struct SymbolicSuperRegionDerived : SymbolicSuperRegionBase {
+  SymbolicSuperRegionBase *bptr; // no-crash
+  SymbolicSuperRegionDerived(SymbolicSuperRegionBase *bptr) : bptr(bptr) {}
+};
+
+SymbolicSuperRegionDerived *getSymbolicRe

[PATCH] D51531: [analyzer][UninitializedObjectChecker] Uninit regions are only reported once

2018-08-31 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: NoQ, george.karpenkov, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

Especially with pointees, it a lot of meaningless reports came from 
uninitialized regions that were already reported.

This is one of a series of patches that aims to drastically cut down the amount 
of reports the checker emits, with the eventual goal being re-enabling 
dereferencing by default and moving out of alpha.


Repository:
  rC Clang

https://reviews.llvm.org/D51531

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -809,3 +809,44 @@
   ReferenceTest4::RecordType c, d{37, 38};
   ReferenceTest4(d, c);
 }
+
+//===--===//
+// Tests for objects containing multiple references to the same object.
+//===--===//
+
+struct IntMultipleReferenceToSameObjectTest {
+  int *iptr; // expected-note{{uninitialized pointee 'this->iptr'}}
+  int &iref; // no-note, pointee of this->iref was already reported
+
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntMultipleReferenceToSameObjectTest(int *i) : iptr(i), iref(*i) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fIntMultipleReferenceToSameObjectTest() {
+  int a;
+  IntMultipleReferenceToSameObjectTest Test(&a);
+}
+
+struct IntReferenceWrapper1 {
+  int &a; // expected-note{{uninitialized pointee 'this->a'}}
+
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntReferenceWrapper1(int &a) : a(a) {} // expected-warning{{1 uninitialized field}}
+};
+
+struct IntReferenceWrapper2 {
+  int &a; // no-note, pointee of this->a was already reported
+
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntReferenceWrapper2(int &a) : a(a) {} // no-warning
+};
+
+void fMultipleObjectsReferencingTheSameObjectTest() {
+  int a;
+
+  IntReferenceWrapper1 T1(a);
+  IntReferenceWrapper2 T2(a);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -126,7 +126,7 @@
 assert(!FR->getDecl()->getType()->isReferenceType() &&
"References must be initialized!");
 return addFieldToUninits(
-LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
+LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
   }
 
   if (!CheckPointeeInitialization) {
@@ -157,8 +157,9 @@
   if (PointeeT->isUnionType()) {
 if (isUnionUninit(R)) {
   if (NeedsCastBack)
-return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
-  return addFieldToUninits(LocalChain.add(LocField(FR)));
+return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
+ R);
+  return addFieldToUninits(LocalChain.add(LocField(FR)), R);
 } else {
   IsAnyFieldInitialized = true;
   return false;
@@ -178,8 +179,8 @@
 
   if (isPrimitiveUninit(PointeeV)) {
 if (NeedsCastBack)
-  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
-return addFieldToUninits(LocalChain.add(LocField(FR)));
+  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
+return addFieldToUninits(LocalChain.add(LocField(FR)), R);
   }
 
   IsAnyFieldInitialized = true;
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -56,9 +56,14 @@
 using namespace clang;
 using namespace clang::ento;
 
+/// We'll mark fields (and pointee of fields) that are confirmed to be
+/// uninitialized as already analyzed.
+REGISTER_SET_WITH_PROGRAMSTATE(AnalyzedRegions, const MemRegion *)
+
 namespace {
 
-class UninitializedObjectChecker : public Checker {
+class UninitializedObjectChecker
+: public Checker {
   std::unique_ptr BT_uninitField;
 
 public:
@@ -69,7 +74,9 @@
 
   UninitializedObjectChecker()
   : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
+
   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
+  void checkDead

[PATCH] D51300: [analyzer][UninitializedObjectChecker] No longer using nonloc::LazyCompoundVal

2018-08-31 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

Would you be comfortable me commiting this without that assert, or should I 
come up with a more risk-free solution?


Repository:
  rC Clang

https://reviews.llvm.org/D51300



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-08-31 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 163499.
Szelethus added a comment.

Reuploaded with `-U9`. Oops.


https://reviews.llvm.org/D51057

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
  test/Analysis/objcpp-uninitialized-object.mm

Index: test/Analysis/objcpp-uninitialized-object.mm
===
--- test/Analysis/objcpp-uninitialized-object.mm
+++ test/Analysis/objcpp-uninitialized-object.mm
@@ -4,7 +4,7 @@
 
 struct StructWithBlock {
   int a;
-  myBlock z; // expected-note{{uninitialized pointer 'this->z'}}
+  myBlock z; // expected-note{{uninitialized field 'this->z'}}
 
   StructWithBlock() : a(0), z(^{}) {}
 
Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -46,6 +46,50 @@
 }
 
 //===--===//
+// Alloca tests.
+//===--===//
+
+struct UntypedAllocaTest {
+  void *allocaPtr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  UntypedAllocaTest() : allocaPtr(__builtin_alloca(sizeof(int))) {
+// All good!
+  }
+};
+
+void fUntypedAllocaTest() {
+  UntypedAllocaTest();
+}
+
+struct TypedAllocaTest1 {
+  int *allocaPtr; // expected-note{{uninitialized pointee 'this->allocaPtr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  TypedAllocaTest1() // expected-warning{{1 uninitialized field}}
+  : allocaPtr(static_cast(__builtin_alloca(sizeof(int {}
+};
+
+void fTypedAllocaTest1() {
+  TypedAllocaTest1();
+}
+
+struct TypedAllocaTest2 {
+  int *allocaPtr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  TypedAllocaTest2()
+  : allocaPtr(static_cast(__builtin_alloca(sizeof(int {
+*allocaPtr = 5;
+// All good!
+  }
+};
+
+void fTypedAllocaTest2() {
+  TypedAllocaTest2();
+}
+
+//===--===//
 // Heap pointer tests.
 //===--===//
 
@@ -203,18 +247,14 @@
   CyclicPointerTest1();
 }
 
-// TODO: Currently, the checker ends up in an infinite loop for the following
-// test case.
-/*
 struct CyclicPointerTest2 {
-  int **pptr;
+  int **pptr; // no-crash
   CyclicPointerTest2() : pptr(reinterpret_cast(&pptr)) {}
 };
 
 void fCyclicPointerTest2() {
   CyclicPointerTest2();
 }
-*/
 
 //===--===//
 // Void pointer tests.
@@ -471,6 +511,39 @@
 }
 
 //===--===//
+// Incomplete pointee tests.
+//===--===//
+
+class IncompleteType;
+
+struct IncompletePointeeTypeTest {
+  IncompleteType *pImpl; //no-crash
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IncompletePointeeTypeTest(IncompleteType *A) : pImpl(A) {}
+};
+
+void fIncompletePointeeTypeTest(void *ptr) {
+  IncompletePointeeTypeTest(reinterpret_cast(ptr));
+}
+
+//===--===//
+// Function pointer tests.
+//===--===//
+
+struct FunctionPointerWithDifferentDynTypeTest {
+  using Func1 = void *(*)();
+  using Func2 = int *(*)();
+
+  Func1 f; // no-crash
+  FunctionPointerWithDifferentDynTypeTest(Func2 f) : f((Func1)f) {}
+};
+
+// Note that there isn't a function calling the constructor of
+// FunctionPointerWithDifferentDynTypeTest, because a crash could only be
+// reproduced without it.
+
+//===--===//
 // Member pointer tests.
 //===--===//
 
@@ -645,6 +718,15 @@
   CyclicList(&n1, int());
 }
 
+struct RingListTest {
+  RingListTest *next; // no-crash
+  RingListTest() : next(this) {}
+};
+
+void fRingListTest() {
+  RingListTest();
+}
+
 //===--===//
 // Tests for classes containing references.
 //===--===//
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -95,11 +95,13 @@
 /// known, and thus FD can not be analyzed.
 static bool isVoi

[PATCH] D51531: [analyzer][UninitializedObjectChecker] Uninit regions are only reported once

2018-08-31 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 163542.

https://reviews.llvm.org/D51531

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -809,3 +809,44 @@
   ReferenceTest4::RecordType c, d{37, 38};
   ReferenceTest4(d, c);
 }
+
+//===--===//
+// Tests for objects containing multiple references to the same object.
+//===--===//
+
+struct IntMultipleReferenceToSameObjectTest {
+  int *iptr; // expected-note{{uninitialized pointee 'this->iptr'}}
+  int &iref; // no-note, pointee of this->iref was already reported
+
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntMultipleReferenceToSameObjectTest(int *i) : iptr(i), iref(*i) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fIntMultipleReferenceToSameObjectTest() {
+  int a;
+  IntMultipleReferenceToSameObjectTest Test(&a);
+}
+
+struct IntReferenceWrapper1 {
+  int &a; // expected-note{{uninitialized pointee 'this->a'}}
+
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntReferenceWrapper1(int &a) : a(a) {} // expected-warning{{1 uninitialized field}}
+};
+
+struct IntReferenceWrapper2 {
+  int &a; // no-note, pointee of this->a was already reported
+
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntReferenceWrapper2(int &a) : a(a) {} // no-warning
+};
+
+void fMultipleObjectsReferencingTheSameObjectTest() {
+  int a;
+
+  IntReferenceWrapper1 T1(a);
+  IntReferenceWrapper2 T2(a);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -126,7 +126,7 @@
 assert(!FR->getDecl()->getType()->isReferenceType() &&
"References must be initialized!");
 return addFieldToUninits(
-LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
+LocalChain.add(LocField(FR, /*IsDereferenced*/ false)), FR);
   }
 
   if (!CheckPointeeInitialization) {
@@ -157,8 +157,9 @@
   if (PointeeT->isUnionType()) {
 if (isUnionUninit(R)) {
   if (NeedsCastBack)
-return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
-  return addFieldToUninits(LocalChain.add(LocField(FR)));
+return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
+ R);
+  return addFieldToUninits(LocalChain.add(LocField(FR)), R);
 } else {
   IsAnyFieldInitialized = true;
   return false;
@@ -178,8 +179,8 @@
 
   if (isPrimitiveUninit(PointeeV)) {
 if (NeedsCastBack)
-  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
-return addFieldToUninits(LocalChain.add(LocField(FR)));
+  return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
+return addFieldToUninits(LocalChain.add(LocField(FR)), R);
   }
 
   IsAnyFieldInitialized = true;
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -56,9 +56,14 @@
 using namespace clang;
 using namespace clang::ento;
 
+/// We'll mark fields (and pointee of fields) that are confirmed to be
+/// uninitialized as already analyzed.
+REGISTER_SET_WITH_PROGRAMSTATE(AnalyzedRegions, const MemRegion *)
+
 namespace {
 
-class UninitializedObjectChecker : public Checker {
+class UninitializedObjectChecker
+: public Checker {
   std::unique_ptr BT_uninitField;
 
 public:
@@ -69,7 +74,9 @@
 
   UninitializedObjectChecker()
   : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
+
   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
+  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
 };
 
 /// A basic field type, that is not a pointer or a reference, it's dynamic and
@@ -166,20 +173,28 @@
   FindUninitializedFields F(Context.getState(), Object->getRegion(),
 CheckPointeeInitialization);
 
-  const UninitFieldMap &UninitFields = F.getUninitFields();
+  std::pair UninitInfo =
+  F.getResults();
+
+  ProgramStateRef UpdatedState = UninitInfo.first;
+  const UninitFieldMap &UninitFields =

[PATCH] D51300: [analyzer][UninitializedObjectChecker] No longer using nonloc::LazyCompoundVal

2018-09-04 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 163813.
Szelethus added a comment.

Fixed a crash where the returned region's type wasn't `CXXRecordDecl`. I'm not 
even sure how this is possible -- and unfortunately I've been unable to create 
a minimal (not) working example for this, and I wasn't even able to recreate 
the error locally. However, on the server where I could repeatedly cause a 
crash with the analysis of `lib/AST/Expr.cpp`, this fix resolved the issue.

Note that this assert failure didn't happen inside `willBeAnalyzedLater`, where 
`getConstructedRegion` is used with a different `CXXConstructorDecl` then the 
one on top of the stack frame.


https://reviews.llvm.org/D51300

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp


Index: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -124,12 +124,11 @@
 
 // Utility function declarations.
 
-/// Returns the object that was constructed by CtorDecl, or None if that isn't
-/// possible.
-// TODO: Refactor this function so that it returns the constructed object's
-// region.
-static Optional
-getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
+/// Returns the region that was constructed by CtorDecl, or nullptr if that
+/// isn't possible.
+static const TypedValueRegion *
+getConstructedRegion(const CXXConstructorDecl *CtorDecl,
+ CheckerContext &Context);
 
 /// Checks whether the object constructed by \p Ctor will be analyzed later
 /// (e.g. if the object is a field of another object, in which case we'd check
@@ -159,12 +158,11 @@
   if (willObjectBeAnalyzedLater(CtorDecl, Context))
 return;
 
-  Optional Object = getObjectVal(CtorDecl, Context);
-  if (!Object)
+  const TypedValueRegion *R = getConstructedRegion(CtorDecl, Context);
+  if (!R)
 return;
 
-  FindUninitializedFields F(Context.getState(), Object->getRegion(),
-CheckPointeeInitialization);
+  FindUninitializedFields F(Context.getState(), R, CheckPointeeInitialization);
 
   const UninitFieldMap &UninitFields = F.getUninitFields();
 
@@ -443,25 +441,27 @@
 //   Utility functions.
 
//===--===//
 
-static Optional
-getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context) {
+static const TypedValueRegion *
+getConstructedRegion(const CXXConstructorDecl *CtorDecl,
+ CheckerContext &Context) {
 
-  Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl->getParent(),
+  Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl,
 Context.getStackFrame());
-  // Getting the value for 'this'.
-  SVal This = Context.getState()->getSVal(ThisLoc);
 
-  // Getting the value for '*this'.
-  SVal Object = Context.getState()->getSVal(This.castAs());
+  SVal ObjectV = Context.getState()->getSVal(ThisLoc);
 
-  return Object.getAs();
+  auto *R = ObjectV.getAsRegion()->getAs();
+  if (R && !R->getValueType()->getAsCXXRecordDecl())
+return nullptr;
+
+  return R;
 }
 
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
   CheckerContext &Context) {
 
-  Optional CurrentObject = getObjectVal(Ctor, 
Context);
-  if (!CurrentObject)
+  const TypedValueRegion *CurrRegion = getConstructedRegion(Ctor, Context);
+  if (!CurrRegion)
 return false;
 
   const LocationContext *LC = Context.getLocationContext();
@@ -472,14 +472,14 @@
 if (!OtherCtor)
   continue;
 
-Optional OtherObject =
-getObjectVal(OtherCtor, Context);
-if (!OtherObject)
+const TypedValueRegion *OtherRegion =
+getConstructedRegion(OtherCtor, Context);
+if (!OtherRegion)
   continue;
 
-// If the CurrentObject is a subregion of OtherObject, it will be analyzed
-// during the analysis of OtherObject.
-if (CurrentObject->getRegion()->isSubRegionOf(OtherObject->getRegion()))
+// If the CurrRegion is a subregion of OtherRegion, it will be analyzed
+// during the analysis of OtherRegion.
+if (CurrRegion->isSubRegionOf(OtherRegion))
   return true;
   }
 


Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -124,12 +124,11 @@
 
 // Utility function declarations.
 
-/// Returns the object that was constructed by CtorDecl, or None if that isn't
-/// possible.
-// TODO: Refactor this function so 

[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-09-05 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 163992.
Szelethus added a comment.

Fixed an assertation failure where a lambda field's this capture was undefined.


https://reviews.llvm.org/D51057

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
  test/Analysis/cxx-uninitialized-object.cpp
  test/Analysis/objcpp-uninitialized-object.mm

Index: test/Analysis/objcpp-uninitialized-object.mm
===
--- test/Analysis/objcpp-uninitialized-object.mm
+++ test/Analysis/objcpp-uninitialized-object.mm
@@ -4,7 +4,7 @@
 
 struct StructWithBlock {
   int a;
-  myBlock z; // expected-note{{uninitialized pointer 'this->z'}}
+  myBlock z; // expected-note{{uninitialized field 'this->z'}}
 
   StructWithBlock() : a(0), z(^{}) {}
 
Index: test/Analysis/cxx-uninitialized-object.cpp
===
--- test/Analysis/cxx-uninitialized-object.cpp
+++ test/Analysis/cxx-uninitialized-object.cpp
@@ -1,11 +1,11 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
 // RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
 // RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
-// RUN:   -std=c++11 -verify  %s
+// RUN:   -std=c++14 -verify  %s
 
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
 // RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
-// RUN:   -std=c++11 -verify  %s
+// RUN:   -std=c++14 -verify  %s
 
 //===--===//
 // Default constructor test.
@@ -781,7 +781,7 @@
 
 void fLambdaTest2() {
   int b;
-  auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized pointee 'this->functor.b'}}
+  auto equals = [&b](int a) { return a == b; }; // expected-note{{uninitialized pointee 'this->functor./*captured variable*/b'}}
   LambdaTest2(equals, int());
 }
 #else
@@ -803,8 +803,8 @@
 namespace LT3Detail {
 
 struct RecordType {
-  int x; // expected-note{{uninitialized field 'this->functor.rec1.x'}}
-  int y; // expected-note{{uninitialized field 'this->functor.rec1.y'}}
+  int x; // expected-note{{uninitialized field 'this->functor./*captured variable*/rec1.x'}}
+  int y; // expected-note{{uninitialized field 'this->functor./*captured variable*/rec1.y'}}
 };
 
 } // namespace LT3Detail
@@ -857,8 +857,8 @@
 
 void fMultipleLambdaCapturesTest1() {
   int b1, b2 = 3, b3;
-  auto equals = [&b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized pointee 'this->functor.b1'}}
-  // expected-note@-1{{uninitialized pointee 'this->functor.b3'}}
+  auto equals = [&b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized pointee 'this->functor./*captured variable*/b1'}}
+  // expected-note@-1{{uninitialized pointee 'this->functor./*captured variable*/b3'}}
   MultipleLambdaCapturesTest1(equals, int());
 }
 
@@ -872,10 +872,35 @@
 
 void fMultipleLambdaCapturesTest2() {
   int b1, b2 = 3, b3;
-  auto equals = [b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized pointee 'this->functor.b3'}}
+  auto equals = [b1, &b2, &b3](int a) { return a == b1 == b2 == b3; }; // expected-note{{uninitialized pointee 'this->functor./*captured variable*/b3'}}
   MultipleLambdaCapturesTest2(equals, int());
 }
 
+struct LambdaWrapper {
+  void *func; // no-crash
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  LambdaWrapper(void *ptr) : func(ptr) {} // expected-warning{{1 uninitialized field}}
+};
+
+struct ThisCapturingLambdaFactory {
+  int a; // expected-note{{uninitialized field 'static_cast(this->func)->/*'this' capture*/->a'}}
+
+  auto ret() {
+return [this] { (void)this; };
+  }
+};
+
+void fLambdaFieldWithInvalidThisCapture() {
+  void *ptr;
+  {
+ThisCapturingLambdaFactory a;
+decltype(a.ret()) lambda = a.ret();
+ptr = λ
+  }
+  LambdaWrapper t(ptr);
+}
+
 //===--===//
 // System header tests.
 //===--===//
Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -46,6 +46,50 @@
 }
 
 //===--===//
+// Alloca tests.
+//===--===//
+
+struct UntypedAllocaTest {
+  void *allocaPtr;
+

[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-09-05 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp:126-127
   if (V.isUndef()) {
+assert(!FR->getDecl()->getType()->isReferenceType() &&
+   "References must be initialized!");
 return addFieldToUninits(

NoQ wrote:
> Good catch.
> 
> It might still be possible to initialize a reference with an 
> already-undefined pointer if core checkers are turned off, but we don't 
> support turning them off, so i guess it's fine.
I removed it, because it did crash couple times on LLVM. Note that the assert 
checked whether the reference for undefined, not uninitialized :/.

It's no longer in the code, but this was it:
```
assert(!FR->getDecl()->getType()->isReferenceType() &&
   "References must be initialized!");
```



Comment at: test/Analysis/cxx-uninitialized-object.cpp:879-902
+struct LambdaWrapper {
+  void *func; // no-crash
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  LambdaWrapper(void *ptr) : func(ptr) {} // expected-warning{{1 uninitialized 
field}}
+};
+

I'm 99% sure this is a FP, but it doesn't originate from the checker. Shouldn't 
`*ptr` be undef after the end of the code block as `lambda`'s lifetime ends?

Nevertheless, it did cause a crash, so here's a quick fix for it.


https://reviews.llvm.org/D51057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51417: [analyzer][UninitializedObjectChecker] Updated comments

2018-09-05 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

Polite ping ^-^


Repository:
  rC Clang

https://reviews.llvm.org/D51417



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51679: [analyzer][UninitializedObjectChecker] Refactored checker options

2018-09-05 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: george.karpenkov, NoQ, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

Since I plan to add a number of new flags, it made sense to encapsulate them in 
a new struct, in order not to pollute `FindUninitializedFields`s constructor 
with new boolean options with super long names.

This revision practically reverts https://reviews.llvm.org/D50508, since 
`FindUninitializedFields` now accesses the pedantic flag anyways. I guess that 
revision was a poor design choice :^).


Repository:
  rC Clang

https://reviews.llvm.org/D51679

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -10,11 +10,8 @@
 // This file defines functions and methods for handling pointers and references
 // to reduce the size and complexity of UninitializedObjectChecker.cpp.
 //
-// To read about command line options and a description what this checker does,
-// refer to UninitializedObjectChecker.cpp.
-//
-// To read about how the checker works, refer to the comments in
-// UninitializedObject.h.
+// To read about command line options and documentation about how the checker
+// works, refer to UninitializedObjectChecker.h.
 //
 //===--===//
 
@@ -127,7 +124,7 @@
 LocalChain.add(LocField(FR, /*IsDereferenced*/ false)));
   }
 
-  if (!CheckPointeeInitialization) {
+  if (!Opts.CheckPointeeInitialization) {
 IsAnyFieldInitialized = true;
 return false;
   }
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -10,36 +10,8 @@
 // This file defines a checker that reports uninitialized fields in objects
 // created after a constructor call.
 //
-// This checker has several options:
-//   - "Pedantic" (boolean). If its not set or is set to false, the checker
-// won't emit warnings for objects that don't have at least one initialized
-// field. This may be set with
-//
-// `-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true`.
-//
-//   - "NotesAsWarnings" (boolean). If set to true, the checker will emit a
-// warning for each uninitalized field, as opposed to emitting one warning
-// per constructor call, and listing the uninitialized fields that belongs
-// to it in notes. Defaults to false.
-//
-// `-analyzer-config \
-// alpha.cplusplus.UninitializedObject:NotesAsWarnings=true`.
-//
-//   - "CheckPointeeInitialization" (boolean). If set to false, the checker will
-// not analyze the pointee of pointer/reference fields, and will only check
-// whether the object itself is initialized. Defaults to false.
-//
-// `-analyzer-config \
-// alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true`.
-//
-// TODO: With some clever heuristics, some pointers should be dereferenced
-// by default. For example, if the pointee is constructed within the
-// constructor call, it's reasonable to say that no external object
-// references it, and we wouldn't generate multiple report on the same
-// pointee.
-//
-// To read about how the checker works, refer to the comments in
-// UninitializedObject.h.
+// To read about command line options and how the checker works, refer to the
+// top of the file and inline comments in UninitializedObject.h.
 //
 // Some of the logic is implemented in UninitializedPointee.cpp, to reduce the
 // complexity of this file.
@@ -62,10 +34,8 @@
   std::unique_ptr BT_uninitField;
 
 public:
-  // These fields will be initialized when registering the checker.
-  bool IsPedantic;
-  bool ShouldConvertNotesToWarnings;
-  bool CheckPointeeInitialization;
+  // The fields of this struct will be initialized when registering the checker.
+  UninitObjCheckerOptions Opts;
 
   UninitializedObjectChecker()
   : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
@@ -163,20 +133,13 @@
   if (!Object)
 return;
 
-  FindUninitializedFields F(Context.getState(), Object->getRegion(),
-CheckPointeeInitialization);
+  FindUninitializedFields F(Context.getState(), Object->getRegion(), Opts);
 
   const UninitFieldMap &UninitFields = F.getUninitFields();

[PATCH] D51680: [analyzer][UninitializedObjectChecker] New flag to ignore union-like constructs

2018-09-05 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: george.karpenkov, NoQ, rnkovacs, xazax.hun.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

Based on a suggestion from @george.karpenkov.

In some cases, structs are used as unions with a help of a tag/kind field. This 
patch adds a new flag, which will ignore these constructs when enabled.

I decided to set this to false by default, out of fear that fields like this 
might refer to the dynamic type of the object.

For more info refer to 
http://lists.llvm.org/pipermail/cfe-dev/2018-August/058906.html and to the 
responses to that, especially 
http://lists.llvm.org/pipermail/cfe-dev/2018-August/059215.html.


Repository:
  rC Clang

https://reviews.llvm.org/D51680

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp

Index: test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
===
--- /dev/null
+++ test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
@@ -0,0 +1,110 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:IgnoreUnionlikeConstructs=true \
+// RUN:   -std=c++11 -verify  %s
+
+// expected-no-diagnostics
+
+// Both type and name contains "kind".
+struct UnionLikeStruct1 {
+  enum Kind {
+volume,
+area
+  } kind;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct1(Kind kind, int Val) : kind(kind) {
+switch (kind) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct1() {
+  UnionLikeStruct1 t(UnionLikeStruct1::volume, 10);
+}
+
+// Only name contains "kind".
+struct UnionLikeStruct2 {
+  enum Type {
+volume,
+area
+  } kind;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct2(Type kind, int Val) : kind(kind) {
+switch (kind) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct2() {
+  UnionLikeStruct2 t(UnionLikeStruct2::volume, 10);
+}
+
+// Only type contains "kind".
+struct UnionLikeStruct3 {
+  enum Kind {
+volume,
+area
+  } type;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct3(Kind type, int Val) : type(type) {
+switch (type) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct3() {
+  UnionLikeStruct3 t(UnionLikeStruct3::volume, 10);
+}
+
+// Only type contains "tag".
+struct UnionLikeStruct4 {
+  enum Tag {
+volume,
+area
+  } type;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct4(Tag type, int Val) : type(type) {
+switch (type) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct4() {
+  UnionLikeStruct4 t(UnionLikeStruct4::volume, 10);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -107,6 +107,11 @@
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
   CheckerContext &Context);
 
+/// Checks whether RD is a union-like construct. We'll consider a RecordDecl
+/// union-like, if it has a field that has [Kk]ind or [Tt]ag in it's identifier
+/// or type name.
+static bool isUnionLike(const RecordDecl *RD);
+
 //===--===//
 //  Methods for UninitializedObjectChecker.
 //===--===//
@@ -223,6 +228,11 @@
   R->getValueType()->getAs()->getDecl()->getDefinition();
   assert(RD && "Referred record has no definition");
 
+  if (Opts.IgnoreUnionlikeConstructs && isUnionLike(RD)) {
+IsAnyFieldInitialized = true;
+return false;
+  }
+
   bool ContainsUninitField = false;
 
   // Are all of this non-union's fields initialized?
@@ -454,6 +464,19 @@
   return false;
 }
 
+static bool isUnionLike(const RecordDecl *RD) {
+  llvm::Regex ContainsKindOrTag("[kK]ind|[tT]ag");
+
+  for (const FieldDecl *FD : RD->fields()) {
+if (ContainsKindOrTag.match(FD->getType().getAsString()))
+  return true;
+if (ContainsKindOrTag.match(FD->getName()))
+  return true;
+  }
+
+  return false;
+}
+
 StringRef clang::ento::getVariableName(const FieldDecl *Field) {
  

[PATCH] D51680: [analyzer][UninitializedObjectChecker] New flag to ignore union-like constructs

2018-09-05 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 164050.
Szelethus added a comment.

Added doc to `www/analyzer/alpha_checks.html`.


https://reviews.llvm.org/D51680

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
  www/analyzer/alpha_checks.html

Index: www/analyzer/alpha_checks.html
===
--- www/analyzer/alpha_checks.html
+++ www/analyzer/alpha_checks.html
@@ -356,6 +356,11 @@
 whether the object itself is initialized. Defaults to false. 
 -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true.
   
+  "IgnoreUnionlikeConstructs" (boolean). If set to false, the checker will
+ not analyze structures that have a field a name or type name that
+ contains [Tt]ag or [Kk]ind. Defaults to false. 
+ -analyzer-config alpha.cplusplus.UninitializedObject:IgnoreUnionlikeConstructs=true.
+  
 
 
 
Index: test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
===
--- /dev/null
+++ test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
@@ -0,0 +1,110 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:IgnoreUnionlikeConstructs=true \
+// RUN:   -std=c++11 -verify  %s
+
+// expected-no-diagnostics
+
+// Both type and name contains "kind".
+struct UnionLikeStruct1 {
+  enum Kind {
+volume,
+area
+  } kind;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct1(Kind kind, int Val) : kind(kind) {
+switch (kind) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct1() {
+  UnionLikeStruct1 t(UnionLikeStruct1::volume, 10);
+}
+
+// Only name contains "kind".
+struct UnionLikeStruct2 {
+  enum Type {
+volume,
+area
+  } kind;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct2(Type kind, int Val) : kind(kind) {
+switch (kind) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct2() {
+  UnionLikeStruct2 t(UnionLikeStruct2::volume, 10);
+}
+
+// Only type contains "kind".
+struct UnionLikeStruct3 {
+  enum Kind {
+volume,
+area
+  } type;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct3(Kind type, int Val) : type(type) {
+switch (type) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct3() {
+  UnionLikeStruct3 t(UnionLikeStruct3::volume, 10);
+}
+
+// Only type contains "tag".
+struct UnionLikeStruct4 {
+  enum Tag {
+volume,
+area
+  } type;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct4(Tag type, int Val) : type(type) {
+switch (type) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct4() {
+  UnionLikeStruct4 t(UnionLikeStruct4::volume, 10);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -107,6 +107,11 @@
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
   CheckerContext &Context);
 
+/// Checks whether RD is a union-like construct. We'll consider a RecordDecl
+/// union-like, if it has a field that has [Kk]ind or [Tt]ag in it's identifier
+/// or type name.
+static bool isUnionLike(const RecordDecl *RD);
+
 //===--===//
 //  Methods for UninitializedObjectChecker.
 //===--===//
@@ -223,6 +228,11 @@
   R->getValueType()->getAs()->getDecl()->getDefinition();
   assert(RD && "Referred record has no definition");
 
+  if (Opts.IgnoreUnionlikeConstructs && isUnionLike(RD)) {
+IsAnyFieldInitialized = true;
+return false;
+  }
+
   bool ContainsUninitField = false;
 
   // Are all of this non-union's fields initialized?
@@ -454,6 +464,19 @@
   return false;
 }
 
+static bool isUnionLike(const RecordDecl *RD) {
+  llvm::Regex ContainsKindOrTag("[kK]ind|[tT]ag");
+
+  for (const FieldDecl *FD : RD->fields()) {
+if (ContainsKindOrTag.match(FD->getType().getAsString()))
+  return true;
+if (ContainsKindOrTag.match(FD->getName()))
+  return true;
+  }
+
+  return fa

[PATCH] D51300: [analyzer][UninitializedObjectChecker] No longer using nonloc::LazyCompoundVal

2018-09-05 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus planned changes to this revision.
Szelethus added a comment.

> Sounds like a test case would be great to have.

Aye. I'd be good to land this with that testcase. There are a variety of other 
projects I'm working on (related to the checker), and none of them depend on 
this patch, so I'll commit this once I figure out how to use `creduce` ><


https://reviews.llvm.org/D51300



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50488: [Analyzer] Checker for non-determinism caused by sorting of pointer-like elements

2018-09-05 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

> How then do you think I should try matching the IntPointerArray example? I am 
> now leaning towards not doing this via AST Matchers as I am not sure if I can 
> easily match more complex cases.

I've sadly reached the end of my knowledge on AST based analysis, but just to 
throw this in there, are you aware of this amazing guide about the static 
analyzer? https://github.com/haoNoQ/clang-analyzer-guide/releases There are a 
couple sections I believe could help you.




Comment at: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp:108-110
+void ento::registerPointerSortingChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker();
+}

whisperity wrote:
> Speaking of not being applicable to C code, I think this snippet here should 
> allow you to skip running the checker if you are not on a C++ file:
> 
> ```
> if (!Mgr.getLangOpts().CPlusPlus)
>   return;
> ```
Actually, I'm very much shooting in the dark here, but wouldn't this work with 
objective C++?


https://reviews.llvm.org/D50488



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51057: [analyzer][UninitializedObjectChecker] Fixed dereferencing

2018-09-07 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: test/Analysis/cxx-uninitialized-object.cpp:879-902
+struct LambdaWrapper {
+  void *func; // no-crash
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  LambdaWrapper(void *ptr) : func(ptr) {} // expected-warning{{1 uninitialized 
field}}
+};
+

NoQ wrote:
> Szelethus wrote:
> > I'm 99% sure this is a FP, but it doesn't originate from the checker. 
> > Shouldn't `*ptr` be undef after the end of the code block as `lambda`'s 
> > lifetime ends?
> > 
> > Nevertheless, it did cause a crash, so here's a quick fix for it.
> I'm pretty sure that all sorts of contents of `lambda` aka `*ptr` are 
> undefined once it goes out of scope. Moreover, `ptr` is now a dangling 
> pointer, and reading from it would cause undefined behavior. I'm not sure if 
> the analyzer actually models this though. 
> 
> But on the other hand, even if it didn't go out of scope, i don't really see 
> where field `a` was initialized here.
> 
> Soo what makes you think it's a false positive?
> Soo what makes you think it's a false positive?

Poor choice of words I guess. Its not a false positive (as the entire region of 
that lambda is undefined), but rather a false negative, as the analyzer doesn't 
pick up that `*ptr` is a dangling pointer.


https://reviews.llvm.org/D51057



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51531: [analyzer][UninitializedObjectChecker] Uninit regions are only reported once

2018-09-07 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

Polite ping :)


https://reviews.llvm.org/D51531



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51866: [analyzer][UninitializedObjectChecker][WIP] New flag to ignore guarded uninitialized fields

2018-09-10 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: george.karpenkov, NoQ, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

This patch is an implementation of the ideas discussed on the mailing list 
. It didn't 
cause any crashes on the already existing test (I checked it by adding the flag 
to them and run lit), but then again, I wasn't able to check it on larger code 
bases just yet, and the LLVM codebase tends to have a couple tricks up it's 
sleeve, so be beware of that.


Repository:
  rC Clang

https://reviews.llvm.org/D51866

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-unguarded-access.cpp

Index: test/Analysis/cxx-uninitialized-object-unguarded-access.cpp
===
--- /dev/null
+++ test/Analysis/cxx-uninitialized-object-unguarded-access.cpp
@@ -0,0 +1,257 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:IgnoreGuardedFields=true \
+// RUN:   -std=c++11 -verify  %s
+
+//===--===//
+// Helper functions for tests.
+//===--===//
+void halt() __attribute__((__noreturn__));
+void assert(int b) {
+  if (!b)
+halt();
+}
+
+int rand();
+
+//===--===//
+// Tests for fields properly guarded by asserts.
+//===--===//
+
+class NoUnguardedFieldsTest {
+public:
+  enum Kind {
+V,
+A
+  };
+
+private:
+  int Volume, Area;
+  Kind K;
+
+public:
+  NoUnguardedFieldsTest(Kind K) : K(K) {
+switch (K) {
+case V:
+  Volume = 0;
+  break;
+case A:
+  Area = 0;
+  break;
+}
+  }
+
+  void operator-() {
+assert(K == Kind::A);
+(void)Area;
+  }
+
+  void operator+() {
+assert(K == Kind::V);
+(void)Volume;
+  }
+};
+
+void fNoUnguardedFieldsTest() {
+  NoUnguardedFieldsTest T1(NoUnguardedFieldsTest::Kind::A);
+  NoUnguardedFieldsTest T2(NoUnguardedFieldsTest::Kind::V);
+}
+
+class NoUnguardedFieldsWithUndefMethodTest {
+public:
+  enum Kind {
+V,
+A
+  };
+
+private:
+  int Volume, Area;
+  Kind K;
+
+public:
+  NoUnguardedFieldsWithUndefMethodTest(Kind K) : K(K) {
+switch (K) {
+case V:
+  Volume = 0;
+  break;
+case A:
+  Area = 0;
+  break;
+}
+  }
+
+  void operator-() {
+assert(K == Kind::A);
+(void)Area;
+  }
+
+  void operator+() {
+assert(K == Kind::V);
+(void)Volume;
+  }
+
+  void methodWithoutDefinition();
+};
+
+void fNoUnguardedFieldsWithUndefMethodTest() {
+  NoUnguardedFieldsWithUndefMethodTest
+  T1(NoUnguardedFieldsWithUndefMethodTest::Kind::A);
+  NoUnguardedFieldsWithUndefMethodTest
+  T2(NoUnguardedFieldsWithUndefMethodTest::Kind::V);
+}
+
+class UnguardedFieldThroughMethodTest {
+public:
+  enum Kind {
+V,
+A
+  };
+
+public:
+  int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}}
+  Kind K;
+
+public:
+  UnguardedFieldThroughMethodTest(Kind K) : K(K) {
+switch (K) {
+case V:
+  Volume = 0;
+  break;
+case A:
+  Area = 0; // expected-warning {{1 uninitialized field}}
+  break;
+}
+  }
+
+  void operator-() {
+assert(K == Kind::A);
+(void)Area;
+  }
+
+  void operator+() {
+(void)Volume;
+  }
+};
+
+void fUnguardedFieldThroughMethodTest() {
+  UnguardedFieldThroughMethodTest T1(UnguardedFieldThroughMethodTest::Kind::A);
+}
+
+class UnguardedPublicFieldsTest {
+public:
+  enum Kind {
+V,
+A
+  };
+
+  int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}}
+  Kind K;
+
+public:
+  UnguardedPublicFieldsTest(Kind K) : K(K) {
+switch (K) {
+case V:
+  Volume = 0;
+  break;
+case A:
+  Area = 0; // expected-warning {{1 uninitialized field}}
+  break;
+}
+  }
+
+  void operator-() {
+assert(K == Kind::A);
+(void)Area;
+  }
+
+  void operator+() {
+assert(K == Kind::V);
+(void)Volume;
+  }
+};
+
+void fUnguardedPublicFieldsTest() {
+  UnguardedPublicFieldsTest T1(UnguardedPublicFieldsTest::Kind::A);
+}
+
+//===--===//
+// Highlights of some false negatives due to syntactic checking.
+//===--===//
+
+class UnguardedFalseNegativeTest1 {
+public:
+  enum Kind {
+V,
+A
+  };
+
+private:
+  int Volume, 

[PATCH] D51680: [analyzer][UninitializedObjectChecker] New flag to ignore records based on it's fields

2018-09-10 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 164696.
Szelethus retitled this revision from "[analyzer][UninitializedObjectChecker] 
New flag to ignore union-like constructs" to 
"[analyzer][UninitializedObjectChecker] New flag to ignore records based on 
it's fields".
Szelethus edited the summary of this revision.
Szelethus added a comment.

Generalized the patch so that the user can supply the pattern that is matched 
against the fields of the records.


https://reviews.llvm.org/D51680

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
  lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
  www/analyzer/alpha_checks.html

Index: www/analyzer/alpha_checks.html
===
--- www/analyzer/alpha_checks.html
+++ www/analyzer/alpha_checks.html
@@ -356,6 +356,13 @@
 whether the object itself is initialized. Defaults to false. 
 -analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true.
   
+  
+"IgnoreRecordsWithField" (string). If supplied, the checker will not
+ analyze structures that have a field with a name or type name that
+ matches the given pattern. Defaults to "".
+
+ -analyzer-config alpha.cplusplus.UninitializedObject:IgnoreRecordsWithField="[Tt]ag|[Kk]ind".
+  
 
 
 
Index: test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
===
--- /dev/null
+++ test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
@@ -0,0 +1,136 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN:   -analyzer-config alpha.cplusplus.UninitializedObject:IgnoreRecordsWithField="[Tt]ag|[Kk]ind" \
+// RUN:   -std=c++11 -verify  %s
+
+// expected-no-diagnostics
+
+// Both type and name contains "kind".
+struct UnionLikeStruct1 {
+  enum Kind {
+volume,
+area
+  } kind;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct1(Kind kind, int Val) : kind(kind) {
+switch (kind) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct1() {
+  UnionLikeStruct1 t(UnionLikeStruct1::volume, 10);
+}
+
+// Only name contains "kind".
+struct UnionLikeStruct2 {
+  enum Type {
+volume,
+area
+  } kind;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct2(Type kind, int Val) : kind(kind) {
+switch (kind) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct2() {
+  UnionLikeStruct2 t(UnionLikeStruct2::volume, 10);
+}
+
+// Only type contains "kind".
+struct UnionLikeStruct3 {
+  enum Kind {
+volume,
+area
+  } type;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct3(Kind type, int Val) : type(type) {
+switch (type) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct3() {
+  UnionLikeStruct3 t(UnionLikeStruct3::volume, 10);
+}
+
+// Only type contains "tag".
+struct UnionLikeStruct4 {
+  enum Tag {
+volume,
+area
+  } type;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct4(Tag type, int Val) : type(type) {
+switch (type) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct4() {
+  UnionLikeStruct4 t(UnionLikeStruct4::volume, 10);
+}
+
+// Both name and type name contains but does not equal to tag/kind.
+struct UnionLikeStruct5 {
+  enum WhateverTagBlahBlah {
+volume,
+area
+  } FunnyKindName;
+
+  int Volume;
+  int Area;
+
+  UnionLikeStruct5(WhateverTagBlahBlah type, int Val) : FunnyKindName(type) {
+switch (FunnyKindName) {
+case volume:
+  Volume = Val;
+  break;
+case area:
+  Area = Val;
+  break;
+}
+  }
+};
+
+void fUnionLikeStruct5() {
+  UnionLikeStruct5 t(UnionLikeStruct5::volume, 10);
+}
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -107,6 +107,10 @@
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
   CheckerContext &Context);
 
+/// Checks whether RD contains a field with a name or type name that matches
+/// \p Pattern.
+static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern);
+
 //===--===//
 //  Methods for UninitializedObjectC

[PATCH] D51680: [analyzer][UninitializedObjectChecker] New flag to ignore records based on it's fields

2018-09-10 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus marked an inline comment as done.
Szelethus added inline comments.



Comment at: 
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp:468
+static bool isUnionLike(const RecordDecl *RD) {
+  llvm::Regex ContainsKindOrTag("[kK]ind|[tT]ag");
+

george.karpenkov wrote:
> 1. Since you are using `match`, you would reject an extra prefix - but what 
> about an extra suffix?
> 2. Would it make sense to expose the entire regexp as a flag? Then you could 
> remove the boolean flag (if you can change the regexp to match if only the 
> entire field name matches, then an empty regexp would correspond to "no 
> matches")
1. Added a new test case, seems to be fine ^-^
2. Sounds cool, so I made it happen.


https://reviews.llvm.org/D51680



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51300: [analyzer][UninitializedObjectChecker] No longer using nonloc::LazyCompoundVal

2018-09-10 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

There are some nasty environment issues I'm dealing with, so the issue is the 
lack of a well functioning creduce, but I'll get it done eventually.


https://reviews.llvm.org/D51300



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50892: [analyzer][UninitializedObjectChecker] Correct dynamic type is acquired for record pointees

2018-09-10 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus marked an inline comment as done.
Szelethus added inline comments.



Comment at: test/Analysis/cxx-uninitialized-object-inheritance.cpp:802
+struct DynTBase2 {
+  int x; // expected-note{{uninitialized field 'static_cast(this->bptr)->DynTBase2::x'}}
+};

Szelethus wrote:
> NoQ wrote:
> > Szelethus wrote:
> > > NoQ wrote:
> > > > Mmm, what's the value of casting to derived type and then specifying 
> > > > that we access the field of the base type anyway? Isn't `this->bptr->x` 
> > > > exactly what the user needs to know(?)
> > > True, but it's a one tough job to write `this->bptr->x` here and also a 
> > > correct note message for...
> > I guess don't try too hard, eg. say if it requires something of non-linear 
> > complexity it's probably not worth it (not because it'd be slow but because 
> > it'd be an indication that it might be not worth the effort).
> I actually invested some effort into this and I'm fairly certain I could pull 
> it off with O(n) complexity, but I'll probably just place a TODO in the code 
> for now, as I have other things I really want to get fixed first.
I think I'll leave this as is, it could be done, but it wouldn't be nice, and 
it wouldn't make anyone's life significantly easier. At least this report tells 
you the dynamic type of `this->bptr`, so I guess that's something.


https://reviews.llvm.org/D50892



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   3   4   5   6   >