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<RecordType>()->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) {
   // If Field is a captured lambda variable, Field->getName() will return with
   // an empty string. We can however acquire it's name from the lambda's
@@ -480,4 +503,6 @@
       "NotesAsWarnings", /*DefaultVal*/ false, Chk);
   Opts.CheckPointeeInitialization = Mgr.getAnalyzerOptions().getBooleanOption(
       "CheckPointeeInitialization", /*DefaultVal*/ false, Chk);
+  Opts.IgnoreUnionlikeConstructs = Mgr.getAnalyzerOptions().getBooleanOption(
+      "IgnoreUnionlikeConstructs", /*DefaultVal*/ false, Chk);
 }
Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
===================================================================
--- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
+++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
@@ -35,6 +35,13 @@
 //     `-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`.
+//
 //     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
@@ -61,6 +68,7 @@
   bool IsPedantic;
   bool ShouldConvertNotesToWarnings;
   bool CheckPointeeInitialization;
+  bool IgnoreUnionlikeConstructs;
 };
 
 /// Represent a single field. This is only an interface to abstract away special
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to