forked from OSchip/llvm-project
[analyzer][UninitializedObjectChecker] New flag to ignore records based on it's fields
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 llvm-svn: 342220
This commit is contained in:
parent
6cec6c467c
commit
d6145d9849
|
@ -35,6 +35,13 @@
|
|||
// `-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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue