[clang] df58018 - [analyzer] Get direct binding for specific punned case

via cfe-commits cfe-commits at lists.llvm.org
Thu May 5 02:54:00 PDT 2022


Author: einvbri
Date: 2022-05-05T04:53:45-05:00
New Revision: df5801806d03c22099c85942134ca3004776016b

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

LOG: [analyzer] Get direct binding for specific punned case

Region store was not able to see through this case to the actual
initialized value of STRUCT ff. This change addresses this case by
getting the direct binding. This was found and debugged in a downstream
compiler, with debug guidance from @steakhal. A positive and negative
test case is added.

The specific case where this issue was exposed.

  typedef struct {
    int a:1;
    int b[2];
  } STRUCT;

  int main() {
    STRUCT ff = {0};
    STRUCT* pff = &ff;
    int a = ((int)pff + 1);
    return a;
  }

Reviewed By: steakhal, martong

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

Added: 
    clang/test/Analysis/array-punned-region.c

Modified: 
    clang/lib/StaticAnalyzer/Core/RegionStore.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 20b167c9b3b22..43924cd4b5424 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -2147,8 +2147,13 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
       return UnknownVal();
 
     // Additionally allow introspection of a block's internal layout.
-    if (!hasPartialLazyBinding && !isa<BlockDataRegion>(R->getBaseRegion()))
+    // Try to get direct binding if all other attempts failed thus far.
+    // Else, return UndefinedVal()
+    if (!hasPartialLazyBinding && !isa<BlockDataRegion>(R->getBaseRegion())) {
+      if (const Optional<SVal> &V = B.getDefaultBinding(R))
+        return *V;
       return UndefinedVal();
+    }
   }
 
   // All other values are symbolic.

diff  --git a/clang/test/Analysis/array-punned-region.c b/clang/test/Analysis/array-punned-region.c
new file mode 100644
index 0000000000000..d319fd7367ec5
--- /dev/null
+++ b/clang/test/Analysis/array-punned-region.c
@@ -0,0 +1,39 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -analyzer-config eagerly-assume=false -triple x86_64-pc-linux-gnu %s
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -analyzer-config eagerly-assume=false -triple i386-pc-linux-gnu  %s
+
+int clang_analyzer_eval(int);
+
+typedef struct {
+  int a : 1;
+  int b[2];
+} BITFIELD_CAST;
+
+void array_struct_bitfield_1() {
+  BITFIELD_CAST ff = {0};
+  BITFIELD_CAST *pff = &ff;
+  clang_analyzer_eval(*((int *)pff + 1) == 0); // expected-warning{{TRUE}}
+  ff.b[0] = 3;
+  clang_analyzer_eval(*((int *)pff + 1) == 3); // expected-warning{{TRUE}}
+}
+
+int array_struct_bitfield_2() {
+  BITFIELD_CAST ff = {0};
+  BITFIELD_CAST *pff = &ff;
+  int a = *((int *)pff + 2); // expected-warning{{Assigned value is garbage or undefined [core.uninitialized.Assign]}}
+  return a;
+}
+
+typedef struct {
+  unsigned int a : 1;
+  unsigned int x : 31;
+  unsigned int c : 1;
+  int b[2];
+} mystruct;
+
+void array_struct_bitfield_3() {
+  mystruct ff;
+  mystruct *pff = &ff;
+  ff.b[0] = 3;
+  clang_analyzer_eval(*((int *)pff + 2) == 3); // expected-warning{{TRUE}}
+}


        


More information about the cfe-commits mailing list