[analysis] Discard type qualifiers when casting values retrieved from the Store.
authorArtem Dergachev <artem.dergachev@gmail.com>
Tue, 17 Dec 2019 22:49:53 +0000 (14:49 -0800)
committerArtem Dergachev <artem.dergachev@gmail.com>
Tue, 17 Dec 2019 23:00:41 +0000 (15:00 -0800)
This canonicalizes the representation of unknown pointer symbols,
which reduces the overall confusion in pointer cast representation.

Patch by Vince Bridgers!

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

clang/lib/StaticAnalyzer/Core/Store.cpp
clang/test/Analysis/uninit-val-const-likeness.c [new file with mode: 0644]

index b4ab687..20660d1 100644 (file)
@@ -393,6 +393,11 @@ SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType,
   return UnknownVal();
 }
 
+static bool hasSameUnqualifiedPointeeType(QualType ty1, QualType ty2) {
+  return ty1->getPointeeType().getTypePtr() == 
+    ty2->getPointeeType().getTypePtr();
+}
+
 /// CastRetrievedVal - Used by subclasses of StoreManager to implement
 ///  implicit casts that arise from loads from regions that are reinterpreted
 ///  as another region.
@@ -421,10 +426,11 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
   // FIXME: We really need a single good function to perform casts for us
   // correctly every time we need it.
   if (castTy->isPointerType() && !castTy->isVoidPointerType())
-    if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(V.getAsRegion()))
-      if (SR->getSymbol()->getType().getCanonicalType() !=
-          castTy.getCanonicalType())
-        return loc::MemRegionVal(castRegion(SR, castTy));
+    if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(V.getAsRegion())) {
+      QualType sr = SR->getSymbol()->getType(); 
+      if (!hasSameUnqualifiedPointeeType(sr, castTy))
+          return loc::MemRegionVal(castRegion(SR, castTy));
+    }
 
   return svalBuilder.dispatchCast(V, castTy);
 }
diff --git a/clang/test/Analysis/uninit-val-const-likeness.c b/clang/test/Analysis/uninit-val-const-likeness.c
new file mode 100644 (file)
index 0000000..1ee1aef
--- /dev/null
@@ -0,0 +1,56 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core %s -verify 
+// expected-no-diagnostics
+
+#define SIZE 2
+
+typedef struct {
+  int noOfSymbols;
+} Params;
+
+static void create(const Params * const params, int fooList[]) {
+  int tmpList[SIZE] = {0};
+  for (int i = 0; i < params->noOfSymbols; i++)
+    fooList[i] = tmpList[i];
+}
+
+int work(Params * const params) {
+  int fooList[SIZE];
+  create(params, fooList);
+  int sum = 0;
+  for (int i = 0; i < params->noOfSymbols; i++)
+    sum += fooList[i]; // no-warning
+  return sum;
+}
+
+static void create2(const Params * const * pparams, int fooList[]) {
+  const Params * params = *pparams;
+  int tmpList[SIZE] = {0};
+  for (int i = 0; i < params->noOfSymbols; i++)
+    fooList[i] = tmpList[i];
+}
+
+int work2(const Params * const params) {
+  int fooList[SIZE];
+  create2(&params, fooList);
+  int sum = 0;
+  for (int i = 0; i < params->noOfSymbols; i++)
+    sum += fooList[i]; // no-warning
+  return sum;
+}
+
+static void create3(Params * const * pparams, int fooList[]) {
+  const Params * params = *pparams;
+  int tmpList[SIZE] = {0};
+  for (int i = 0; i < params->noOfSymbols; i++)
+    fooList[i] = tmpList[i];
+}
+
+int work3(const Params * const params) {
+  int fooList[SIZE];
+  Params *const *ptr = (Params *const*)&params;
+  create3(ptr, fooList);
+  int sum = 0;
+  for (int i = 0; i < params->noOfSymbols; i++)
+    sum += fooList[i]; // no-warning
+  return sum;
+}