]> granicus.if.org Git - clang/commitdiff
[analyzer][UninitializedObjectChecker] New flag to ignore records based on it's fields
authorKristof Umann <dkszelethus@gmail.com>
Fri, 14 Sep 2018 10:10:09 +0000 (10:10 +0000)
committerKristof Umann <dkszelethus@gmail.com>
Fri, 14 Sep 2018 10:10:09 +0000 (10:10 +0000)
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 string flag (a pattern), that is matched against the
fields of a record, and should a match be found, the entire record is ignored.

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.

Differential Revision: https://reviews.llvm.org/D51680

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@342220 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp [new file with mode: 0644]
www/analyzer/alpha_checks.html

index fbc241a2831b86ee6ae39c4762aa199bdd040c6f..e1e8cfa58267037dfeb7d98d1273d282a17b8c04 100644 (file)
 //     `-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"`.
+//
 //     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
@@ -60,7 +67,8 @@ namespace ento {
 struct UninitObjCheckerOptions {
   bool IsPedantic = false;
   bool ShouldConvertNotesToWarnings = false;
-  bool CheckPointeeInitialization =  false;
+  bool CheckPointeeInitialization = false;
+  std::string IgnoredRecordsWithFieldPattern;
 };
 
 /// A lightweight polymorphic wrapper around FieldRegion *. We'll use this
index 92e21f9cce9c60a145a0c28914c5523a80f51b3c..b6322293212c9ff648d82a6e3dae8e1dfd8b8747 100644 (file)
@@ -109,6 +109,10 @@ getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
 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 UninitializedObjectChecker.
 //===----------------------------------------------------------------------===//
@@ -228,6 +232,12 @@ bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
     return true;
   }
 
+  if (!Opts.IgnoredRecordsWithFieldPattern.empty() &&
+      shouldIgnoreRecord(RD, Opts.IgnoredRecordsWithFieldPattern)) {
+    IsAnyFieldInitialized = true;
+    return false;
+  }
+
   bool ContainsUninitField = false;
 
   // Are all of this non-union's fields initialized?
@@ -442,6 +452,19 @@ static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
   return false;
 }
 
+static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern) {
+  llvm::Regex R(Pattern);
+
+  for (const FieldDecl *FD : RD->fields()) {
+    if (R.match(FD->getType().getAsString()))
+      return true;
+    if (R.match(FD->getName()))
+      return true;
+  }
+
+  return false;
+}
+
 std::string 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
@@ -472,10 +495,13 @@ void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
   AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
   UninitObjCheckerOptions &ChOpts = Chk->Opts;
 
-  ChOpts.IsPedantic = AnOpts.getBooleanOption(
-      "Pedantic", /*DefaultVal*/ false, Chk);
-  ChOpts.ShouldConvertNotesToWarnings = AnOpts.getBooleanOption(
-      "NotesAsWarnings", /*DefaultVal*/ false, Chk);
+  ChOpts.IsPedantic =
+      AnOpts.getBooleanOption("Pedantic", /*DefaultVal*/ false, Chk);
+  ChOpts.ShouldConvertNotesToWarnings =
+      AnOpts.getBooleanOption("NotesAsWarnings", /*DefaultVal*/ false, Chk);
   ChOpts.CheckPointeeInitialization = AnOpts.getBooleanOption(
       "CheckPointeeInitialization", /*DefaultVal*/ false, Chk);
+  ChOpts.IgnoredRecordsWithFieldPattern =
+      AnOpts.getOptionAsString("IgnoreRecordsWithField",
+                               /*DefaultVal*/ "", Chk);
 }
diff --git a/test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp b/test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
new file mode 100644 (file)
index 0000000..dc52afd
--- /dev/null
@@ -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 837ccce624f3e874242dff18cb1d21cafc230977..53635b7050ba4c7e96963da02a38afc6bbf7590d 100644 (file)
@@ -356,6 +356,13 @@ It has several options:
     whether the object itself is initialized. Defaults to false. <br>
     <code>-analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true</code>.
   </li>
+  <li>
+    "<code>IgnoreRecordsWithField</code>" (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 <code>""</code>.
+
+     <code>-analyzer-config alpha.cplusplus.UninitializedObject:IgnoreRecordsWithField="[Tt]ag|[Kk]ind"</code>.
+  </li>
 </ul></div></div></td>
 <td><div class="exampleContainer expandable">
 <div class="example"><pre>