[clang] 91c07eb - [analyzer] Ignore single element arrays in getStaticSize() conditionally

Balazs Benics via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 4 01:20:53 PDT 2021


Author: Balazs Benics
Date: 2021-09-04T10:19:57+02:00
New Revision: 91c07eb8ee6ea2d48158dce123bac7b7c30eb294

URL: https://github.com/llvm/llvm-project/commit/91c07eb8ee6ea2d48158dce123bac7b7c30eb294
DIFF: https://github.com/llvm/llvm-project/commit/91c07eb8ee6ea2d48158dce123bac7b7c30eb294.diff

LOG: [analyzer] Ignore single element arrays in getStaticSize() conditionally

Quoting https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html:
> In the absence of the zero-length array extension, in ISO C90 the contents
> array in the example above would typically be declared to have a single
> element.

We should not assume that the size of the //flexible array member// field has
a single element, because in some cases they use it as a fallback for not
having the //zero-length array// language extension.
In this case, the analyzer should return `Unknown` as the extent of the field
instead.

Reviewed By: martong

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

Added: 
    

Modified: 
    clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
    clang/lib/StaticAnalyzer/Core/MemRegion.cpp
    clang/test/Analysis/analyzer-config.c
    clang/test/Analysis/flexible-array-members.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
index e97e0a6892a93..16ca7a8456e39 100644
--- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
+++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
@@ -320,6 +320,14 @@ ANALYZER_OPTION(bool, ShouldDisplayCheckerNameForText, "display-checker-name",
                 "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.
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 1a614d4d2bcdb..0358430f519e2 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -28,7 +28,9 @@
 #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"
@@ -770,9 +772,16 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
     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;
@@ -783,6 +792,15 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
         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;
     };

diff  --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c
index c9f9b438bfbb7..bf3335c45083e 100644
--- a/clang/test/Analysis/analyzer-config.c
+++ b/clang/test/Analysis/analyzer-config.c
@@ -31,6 +31,7 @@
 // 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

diff  --git a/clang/test/Analysis/flexible-array-members.c b/clang/test/Analysis/flexible-array-members.c
index 6200ed6d41d27..2c11910fa876e 100644
--- a/clang/test/Analysis/flexible-array-members.c
+++ b/clang/test/Analysis/flexible-array-members.c
@@ -9,6 +9,11 @@
 // 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);
@@ -75,6 +80,26 @@ void test_single_element_array_possible_fam() {
     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 at -2 {{8 S64b}}
+  // expected-warning at -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 at -2 {{8 U64b}}
+  // expected-warning at -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 at -2 {{8 U64b}}
+  // expected-warning at -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));
@@ -93,4 +118,5 @@ void test_single_element_array_possible_fam() {
   // expected-warning at -2 {{8 U64b}}
   // expected-warning at -2 {{4 S64b}}
   free(q);
+#endif
 }


        


More information about the cfe-commits mailing list