From e5646b9254e0150e7897bd2658fa0b19eef39070 Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Wed, 25 Aug 2021 16:47:13 +0200 Subject: [PATCH] Revert "Revert "[analyzer] Ignore IncompleteArrayTypes in getStaticSize() for FAMs"" This reverts commit df1f4e0cc6ec9a734aae41ffd48ee8b2007fcabb. Now the test case explicitly specifies the target triple. I decided to use x86_64 for that matter, to have a fixed bitwidth for `size_t`. Aside from that, relanding the original changes of: https://reviews.llvm.org/D105184 --- clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 23 ++++- clang/test/Analysis/flexible-array-members.c | 96 ++++++++++++++++++++ 2 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 clang/test/Analysis/flexible-array-members.c diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index bd725ee9eaa3..1a614d4d2bcd 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -768,14 +768,27 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR, return UnknownVal(); QualType Ty = cast(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(Ty)) - return UnknownVal(); - } + const auto isFlexibleArrayMemberCandidate = [this](QualType Ty) -> bool { + const ArrayType *AT = Ctx.getAsArrayType(Ty); + if (!AT) + return false; + if (isa(AT)) + return true; + + if (const auto *CAT = dyn_cast(AT)) { + const llvm::APInt &Size = CAT->getSize(); + if (Size.isNullValue()) + return true; + } + return false; + }; + + if (isFlexibleArrayMemberCandidate(Ty)) + return UnknownVal(); return Size; } diff --git a/clang/test/Analysis/flexible-array-members.c b/clang/test/Analysis/flexible-array-members.c new file mode 100644 index 000000000000..6200ed6d41d2 --- /dev/null +++ b/clang/test/Analysis/flexible-array-members.c @@ -0,0 +1,96 @@ +// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c90 +// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c99 +// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c11 +// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c17 + +// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++98 -x c++ +// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++03 -x c++ +// RUN: %clang_analyze_cc1 -triple x86_64-linux-gnu -analyzer-checker=core,unix,debug.ExprInspection %s -verify -std=c++11 -x c++ +// 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++ + +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); +}