"Display the checker name for textual outputs",
true)
+ANALYZER_OPTION(
+ bool, ShouldConsiderSingleElementArraysAsFlexibleArrayMembers,
+ "consider-single-element-arrays-as-flexible-array-members",
+ "Consider single element arrays as flexible array member candidates. "
+ "This will prevent the analyzer from assuming that a single element array "
+ "holds a single element.",
+ false)
+
//===----------------------------------------------------------------------===//
// Unsigned analyzer options.
//===----------------------------------------------------------------------===//
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
const DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB);
- // A zero-length array at the end of a struct often stands for dynamically
- // allocated extra memory.
- const auto isFlexibleArrayMemberCandidate = [this](QualType Ty) -> bool {
+ // We currently don't model flexible array members (FAMs), which are:
+ // - int array[]; of IncompleteArrayType
+ // - int array[0]; of ConstantArrayType with size 0
+ // - int array[1]; of ConstantArrayType with size 1 (*)
+ // (*): Consider single element array object members as FAM candidates only
+ // if the consider-single-element-arrays-as-flexible-array-members
+ // analyzer option is true.
+ // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
+ const auto isFlexibleArrayMemberCandidate = [this,
+ &SVB](QualType Ty) -> bool {
const ArrayType *AT = Ctx.getAsArrayType(Ty);
if (!AT)
return false;
const llvm::APInt &Size = CAT->getSize();
if (Size.isNullValue())
return true;
+
+ // FIXME: Acquire the AnalyzerOptions in a simpler way.
+ const AnalyzerOptions &Opts = SVB.getStateManager()
+ .getOwningEngine()
+ .getAnalysisManager()
+ .getAnalyzerOptions();
+ if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers &&
+ Size.isOneValue())
+ return true;
}
return false;
};
// CHECK-NEXT: cfg-rich-constructors = true
// CHECK-NEXT: cfg-scopes = false
// CHECK-NEXT: cfg-temporary-dtors = true
+// CHECK-NEXT: consider-single-element-arrays-as-flexible-array-members = false
// CHECK-NEXT: core.CallAndMessage:ArgInitializedness = true
// CHECK-NEXT: core.CallAndMessage:ArgPointeeInitializedness = false
// CHECK-NEXT: core.CallAndMessage:CXXDeallocationArg = true
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++14 -x c++
// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++17 -x c++
+// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c17 \
+// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=true -DSINGLE_ELEMENT_FAMS
+// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++17 -x c++ \
+// RUN: -analyzer-config consider-single-element-arrays-as-flexible-array-members=true -DSINGLE_ELEMENT_FAMS
+
typedef __typeof(sizeof(int)) size_t;
size_t clang_analyzer_getExtent(void *);
void clang_analyzer_dump(size_t);
int data[1];
} FAM;
+#ifdef SINGLE_ELEMENT_FAMS
+ FAM likely_fam;
+ clang_analyzer_dump(clang_analyzer_getExtent(&likely_fam));
+ clang_analyzer_dump(clang_analyzer_getExtent(likely_fam.data));
+ // expected-warning@-2 {{8 S64b}}
+ // expected-warning@-2 {{Unknown}}
+
+ FAM *p = (FAM *)alloca(sizeof(FAM));
+ clang_analyzer_dump(clang_analyzer_getExtent(p));
+ clang_analyzer_dump(clang_analyzer_getExtent(p->data));
+ // expected-warning@-2 {{8 U64b}}
+ // expected-warning@-2 {{Unknown}}
+
+ FAM *q = (FAM *)malloc(sizeof(FAM));
+ clang_analyzer_dump(clang_analyzer_getExtent(q));
+ clang_analyzer_dump(clang_analyzer_getExtent(q->data));
+ // expected-warning@-2 {{8 U64b}}
+ // expected-warning@-2 {{Unknown}}
+ free(q);
+#else
FAM likely_fam;
clang_analyzer_dump(clang_analyzer_getExtent(&likely_fam));
clang_analyzer_dump(clang_analyzer_getExtent(likely_fam.data));
// expected-warning@-2 {{8 U64b}}
// expected-warning@-2 {{4 S64b}}
free(q);
+#endif
}