return UnknownVal();
QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
- DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB);
+ const DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB);
// A zero-length array at the end of a struct often stands for dynamically
// allocated extra memory.
- if (Size.isZeroConstant()) {
- if (isa<ConstantArrayType>(Ty))
- return UnknownVal();
- }
+ const auto isFlexibleArrayMemberCandidate = [this](QualType Ty) -> bool {
+ const ArrayType *AT = Ctx.getAsArrayType(Ty);
+ if (!AT)
+ return false;
+ if (isa<IncompleteArrayType>(AT))
+ return true;
+
+ if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ const llvm::APInt &Size = CAT->getSize();
+ if (Size.isNullValue())
+ return true;
+ }
+ return false;
+ };
+
+ if (isFlexibleArrayMemberCandidate(Ty))
+ return UnknownVal();
return Size;
}
--- /dev/null
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c90
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c99
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c11
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c17
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++98 -x c++
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++03 -x c++
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++11 -x c++
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++14 -x c++
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++17 -x c++
+
+typedef __typeof(sizeof(int)) size_t;
+size_t clang_analyzer_getExtent(void *);
+void clang_analyzer_dump(size_t);
+
+void *alloca(size_t size);
+void *malloc(size_t size);
+void free(void *ptr);
+
+void test_incomplete_array_fam() {
+ typedef struct FAM {
+ char c;
+ int data[];
+ } FAM;
+
+ FAM fam;
+ clang_analyzer_dump(clang_analyzer_getExtent(&fam));
+ clang_analyzer_dump(clang_analyzer_getExtent(fam.data));
+ // expected-warning@-2 {{4 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 {{4 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 {{4 U64b}}
+ // expected-warning@-2 {{Unknown}}
+ free(q);
+}
+
+void test_zero_length_array_fam() {
+ typedef struct FAM {
+ char c;
+ int data[0];
+ } FAM;
+
+ FAM fam;
+ clang_analyzer_dump(clang_analyzer_getExtent(&fam));
+ clang_analyzer_dump(clang_analyzer_getExtent(fam.data));
+ // expected-warning@-2 {{4 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 {{4 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 {{4 U64b}}
+ // expected-warning@-2 {{Unknown}}
+ free(q);
+}
+
+void test_single_element_array_possible_fam() {
+ typedef struct FAM {
+ char c;
+ int data[1];
+ } FAM;
+
+ 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 {{4 S64b}}
+
+ 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 {{4 S64b}}
+
+ 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 {{4 S64b}}
+ free(q);
+}