MTC updated this revision to Diff 140629.
MTC added a comment.

> Thank you for your reminding, I overlooked this point. However for 
> non-concrete character, the symbol value, if we just invalidate the region, 
> the constraint information of the non-concrete character will be lost. Do we 
> need to consider this?

Sorry for my hasty question, analyzer does not support to bind a symbol with a 
default binding.

The update of this diff is as follows.

- If the char value is not concrete, just invalidate the region.
- Add a test about symbolic char value.
- A little code refactoring.


Repository:
  rC Clang

https://reviews.llvm.org/D44934

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
  include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
  lib/StaticAnalyzer/Checkers/CStringChecker.cpp
  lib/StaticAnalyzer/Core/ProgramState.cpp
  lib/StaticAnalyzer/Core/RegionStore.cpp
  lib/StaticAnalyzer/Core/Store.cpp
  test/Analysis/bstring.cpp
  test/Analysis/null-deref-ps-region.c
  test/Analysis/string.c

Index: test/Analysis/string.c
===================================================================
--- test/Analysis/string.c
+++ test/Analysis/string.c
@@ -1,7 +1,8 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_analyze_cc1 -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
-// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -DVARIANT -analyzer-checker=alpha.security.taint,core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,unix.Malloc,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,unix.Malloc,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -DVARIANT -analyzer-checker=core,unix.cstring,unix.Malloc,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -DVARIANT -analyzer-checker=alpha.security.taint,core,unix.cstring,unix.Malloc,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
+// RUN: %clang_analyze_cc1 -DSUPPRESS_OUT_OF_BOUND -analyzer-checker=core,unix.cstring,unix.Malloc,alpha.unix.cstring.BufferOverlap,alpha.unix.cstring.NotNullTerminated,debug.ExprInspection -analyzer-store=region -Wno-null-dereference -verify %s
 
 //===----------------------------------------------------------------------===
 // Declarations
@@ -1159,6 +1160,248 @@
   clang_analyzer_eval(str[1] == 'b'); // expected-warning{{UNKNOWN}}
 }
 
+//===----------------------------------------------------------------------===
+// memset()
+//===----------------------------------------------------------------------===
+
+void *memset( void *dest, int ch, size_t count );
+
+void* malloc(size_t size);
+void free(void*);
+
+void memset1_char_array_null() {
+  char str[] = "abcd";
+  clang_analyzer_eval(strlen(str) == 4); // expected-warning{{TRUE}}
+  memset(str, '\0', 2);
+  clang_analyzer_eval(strlen(str) == 0); // expected-warning{{TRUE}}
+}
+
+void memset2_char_array_null() {
+  char str[] = "abcd";
+  clang_analyzer_eval(strlen(str) == 4); // expected-warning{{TRUE}}
+  memset(str, '\0', strlen(str) + 1);
+  clang_analyzer_eval(strlen(str) == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(str[2] == 0);      // expected-warning{{TRUE}}
+}
+
+void memset3_char_malloc_null() {
+  char *str = (char *)malloc(10 * sizeof(char));
+  memset(str + 1, '\0', 8);
+  clang_analyzer_eval(str[1] == 0); // expected-warning{{UNKNOWN}}
+  free(str);
+}
+
+void memset4_char_malloc_null() {
+  char *str = (char *)malloc(10 * sizeof(char));
+  //void *str = malloc(10 * sizeof(char));
+  memset(str, '\0', 10);
+  clang_analyzer_eval(str[1] == 0);      // expected-warning{{TRUE}}
+  clang_analyzer_eval(strlen(str) == 0); // expected-warning{{TRUE}}
+  free(str);
+}
+
+#ifdef SUPPRESS_OUT_OF_BOUND
+void memset5_char_malloc_overflow_null() {
+  char *str = (char *)malloc(10 * sizeof(char));
+  memset(str, '\0', 12);
+  clang_analyzer_eval(str[1] == 0); // expected-warning{{UNKNOWN}}
+  free(str);
+}
+#endif
+
+void memset6_char_array_nonnull() {
+  char str[] = "abcd";
+  clang_analyzer_eval(strlen(str) == 4); // expected-warning{{TRUE}}
+  memset(str, '0', 2);
+  clang_analyzer_eval(str[0] == 'a');    // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(strlen(str) == 4); // expected-warning{{UNKNOWN}}
+}
+
+void memset7_char_array_nonnull() {
+  char str[5] = "abcd";
+  clang_analyzer_eval(strlen(str) == 4); // expected-warning{{TRUE}}
+  memset(str, '0', 5);
+  clang_analyzer_eval(str[0] == '0');    // expected-warning{{TRUE}}
+  clang_analyzer_eval(strlen(str) >= 5); // expected-warning{{TRUE}}
+}
+
+#ifdef SUPPRESS_OUT_OF_BOUND
+void memset8_char_array_nonnull() {
+	char str[5] = "abcd";
+	clang_analyzer_eval(strlen(str) == 4); // expected-warning{{TRUE}}
+	memset(str, '0', 10);
+	clang_analyzer_eval(str[0] != '0'); // expected-warning{{UNKNOWN}}
+	clang_analyzer_eval(strlen(str) >= 10); // expected-warning{{TRUE}}
+	clang_analyzer_eval(strlen(str) < 10); // expected-warning{{FALSE}}
+}
+#endif
+
+struct POD_memset {
+  int num;
+  char c;
+};
+
+void memset10_struct() {
+  struct POD_memset pod;
+  char *str = (char *)&pod;
+  pod.num = 1;
+  pod.c = 1;
+  clang_analyzer_eval(pod.num == 0); // expected-warning{{FALSE}}
+  memset(str, 0, sizeof(struct POD_memset));
+  clang_analyzer_eval(pod.num == 0); // expected-warning{{TRUE}}
+}
+
+#ifdef SUPPRESS_OUT_OF_BOUND
+void memset11_struct_field() {
+  struct POD_memset pod;
+  pod.num = 1;
+  pod.c = '1';
+  memset(&pod.num, 0, sizeof(struct POD_memset));
+
+  clang_analyzer_eval(pod.num == 0);  // expected-warning{{TRUE}}
+  clang_analyzer_eval(pod.c == '\0'); // expected-warning{{TRUE}}
+}
+
+void memset12_struct_field() {
+  struct POD_memset pod;
+  pod.num = 1;
+  pod.c = '1';
+  memset(&pod.c, 0, sizeof(struct POD_memset));
+  clang_analyzer_eval(pod.num == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(pod.c == 0);   // expected-warning{{UNKNOWN}}
+}
+
+union U_memset {
+	int i;
+	double d;
+	char c;
+};
+
+void memset13_union_field() {
+	union U_memset u;
+	u.i = 5;
+	memset(&u.i, '\0', sizeof(union U_memset));
+	// Note: This should be TRUE, analyzer can't handle union perfectly now.
+	clang_analyzer_eval(u.d == 0); // expected-warning{{UNKNOWN}}
+}
+#endif
+
+void memset14_region_cast() {
+	char *str = (char*)malloc(10 * sizeof(int));
+	int *array = (int*)str;
+	memset(array, 0, 10 * sizeof(int));
+	clang_analyzer_eval(str[10] == '\0'); // expected-warning{{TRUE}}
+	clang_analyzer_eval(strlen((char*)array) == 0); // expected-warning{{TRUE}}
+	clang_analyzer_eval(strlen(str) == 0); // expected-warning{{TRUE}}
+	free(str);
+}
+
+void memset15_region_cast() {
+	char *str = (char*)malloc(10 * sizeof(int));
+	int *array = (int*)str;
+	memset(array, 0, 5 * sizeof(int));
+	clang_analyzer_eval(str[10] == '\0'); // expected-warning{{UNKNOWN}}
+	clang_analyzer_eval(strlen((char*)array) == 0); // expected-warning{{TRUE}}
+	clang_analyzer_eval(strlen(str) == 0); // expected-warning{{TRUE}}
+	free(str);
+}
+
+
+void memset16_region_cast() {
+	char *str = (char*)malloc(10 * sizeof(int));
+	int *array = (int*)str;
+	memset(array, '0', 10 * sizeof(int));
+	clang_analyzer_eval(str[10] == '0'); // expected-warning{{TRUE}}
+	clang_analyzer_eval(strlen((char*)array) >= 10 * sizeof(int)); // expected-warning{{TRUE}}
+	clang_analyzer_eval(strlen(str) >= 10 * sizeof(int)); // expected-warning{{TRUE}}
+	free(str);
+}
+
+#ifdef SUPPRESS_OUT_OF_BOUND
+void memset17_region_cast() {
+	char *str = (char*)malloc(10 * sizeof(int));
+	int *array = (int*)str;
+	memset(array, '0', 12 * sizeof(int));
+	clang_analyzer_eval(str[10] == '0'); // expected-warning{{UNKNOWN}}
+	clang_analyzer_eval(strlen((char*)array) >= 12 * sizeof(int)); // expected-warning{{TRUE}}
+	clang_analyzer_eval(strlen(str) >= 12 * sizeof(int)); // expected-warning{{TRUE}}
+	free(str);
+}
+
+void memset18_memset_multiple_times() {
+  char *str = (char *)malloc(10 * sizeof(char));
+  clang_analyzer_eval(strlen(str) == 0); // expected-warning{{UNKNOWN}}
+
+  memset(str + 2, '\0', 10 * sizeof(char));
+  clang_analyzer_eval(strlen(str) == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(str[1] == '\0');   // expected-warning{{UNKNOWN}}
+
+  memset(str, '0', 10 * sizeof(char));
+  clang_analyzer_eval(strlen(str) >= 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(str[1] == '0');     // expected-warning{{TRUE}}
+
+  free(str);
+}
+
+void memset19_memset_multiple_times() {
+  char *str = (char *)malloc(10 * sizeof(char));
+  clang_analyzer_eval(strlen(str) == 0); // expected-warning{{UNKNOWN}}
+
+  memset(str, '0', 10 * sizeof(char));
+  clang_analyzer_eval(strlen(str) >= 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(str[1] == '0');     // expected-warning{{TRUE}}
+
+  memset(str + 2, '\0', 10 * sizeof(char));
+  clang_analyzer_eval(strlen(str) >= 10); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(str[1] == '0');     // expected-warning{{UNKNOWN}}
+
+  free(str);
+}
+#endif
+
+int memset20_scalar() {
+	int *x = malloc(sizeof(int));
+  *x = 10;
+	memset(x, 0, sizeof(int));
+	int num = 1 / *x; // expected-warning{{Division by zero}}
+	free(x);
+  return num;
+}
+
+int memset21_scalar() {
+	int *x = malloc(sizeof(int));
+	memset(x, 0, 1);
+	int num = 1 / *x;
+	free(x);
+  return num;
+}
+
+void memset22_array() {
+  int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  clang_analyzer_eval(array[1] == 2); // expected-warning{{TRUE}}
+  memset(array, 0, sizeof(array));
+  clang_analyzer_eval(array[1] == 0); // expected-warning{{TRUE}}
+}
+
+
+void memset23_array_pod_object() {
+  struct POD_memset array[10];
+  array[1].num = 10;
+  array[1].c = 'c';
+  clang_analyzer_eval(array[1].num == 10); // expected-warning{{TRUE}}
+  memset(&array[1], 0, sizeof(struct POD_memset));
+  clang_analyzer_eval(array[1].num == 0); // expected-warning{{UNKNOWN}}
+}
+
+void memset24_array_pod_object() {
+  struct POD_memset array[10];
+  array[1].num = 10;
+  array[1].c = 'c';
+  clang_analyzer_eval(array[1].num == 10); // expected-warning{{TRUE}}
+  memset(array, 0, sizeof(array));
+  clang_analyzer_eval(array[1].num == 0); // expected-warning{{TRUE}}
+}
+
 //===----------------------------------------------------------------------===
 // FIXMEs
 //===----------------------------------------------------------------------===
@@ -1186,3 +1429,15 @@
 	// This time, we know that y fits in x anyway.
   clang_analyzer_eval(strlen(x) <= 3); // expected-warning{{UNKNOWN}}
 }
+
+// The analyzer does not support binding a symbol with default binding.
+void memset25_symbol(char c) {
+  char array[10] = {0};
+  if (c > 10)
+    return;
+
+  memset(array, c, 10);
+
+  // This should be TRUE.
+  clang_analyzer_eval(array[4] <= 10); // expected-warning{{UNKNOWN}}
+}
Index: test/Analysis/null-deref-ps-region.c
===================================================================
--- test/Analysis/null-deref-ps-region.c
+++ test/Analysis/null-deref-ps-region.c
@@ -22,7 +22,7 @@
 void foo() {
   int *x = malloc(sizeof(int));
   memset(x, 0, sizeof(int));
-  int n = 1 / *x; // FIXME: no-warning
+  int n = 1 / *x; // expected-warning {{Division by zero}}
   free(x);
 }
 
Index: test/Analysis/bstring.cpp
===================================================================
--- test/Analysis/bstring.cpp
+++ test/Analysis/bstring.cpp
@@ -1,7 +1,8 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_analyze_cc1 -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
-// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,unix.Malloc,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,unix.Malloc,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DSUPPRESS_OUT_OF_BOUND -analyzer-checker=core,unix.cstring,unix.Malloc,alpha.unix.cstring.BufferOverlap,alpha.unix.cstring.NotNullTerminated,debug.ExprInspection -analyzer-store=region -verify %s
 
 #include "Inputs/system-header-simulator-cxx.h"
 #include "Inputs/system-header-simulator-for-malloc.h"
@@ -77,3 +78,118 @@
   unsigned *f;
 };
 }
+
+void *memset(void *dest, int ch, std::size_t count);
+namespace memset_non_pod {
+class Base {
+public:
+  int b_mem;
+  Base() : b_mem(1) {}
+};
+
+class Derived : public Base {
+public:
+  int d_mem;
+  Derived() : d_mem(2) {}
+};
+
+void memset1_inheritance() {
+  Derived d;
+  memset(&d, 0, sizeof(Derived));
+  clang_analyzer_eval(d.b_mem == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(d.d_mem == 0); // expected-warning{{TRUE}}
+}
+
+#ifdef SUPPRESS_OUT_OF_BOUND
+void memset2_inheritance_field() {
+  Derived d;
+  memset(&d.d_mem, 0, sizeof(Derived));
+  clang_analyzer_eval(d.b_mem == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(d.d_mem == 0); // expected-warning{{UNKNOWN}}
+}
+
+void memset3_inheritance_field() {
+  Derived d;
+  memset(&d.b_mem, 0, sizeof(Derived));
+  clang_analyzer_eval(d.b_mem == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(d.d_mem == 0); // expected-warning{{TRUE}}
+}
+#endif
+
+void memset4_array_nonpod_object() {
+  Derived array[10];
+  clang_analyzer_eval(array[1].b_mem == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(array[1].d_mem == 2); // expected-warning{{UNKNOWN}}
+  memset(&array[1], 0, sizeof(Derived));
+  clang_analyzer_eval(array[1].b_mem == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(array[1].d_mem == 0); // expected-warning{{UNKNOWN}}
+}
+
+void memset5_array_nonpod_object() {
+  Derived array[10];
+  clang_analyzer_eval(array[1].b_mem == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(array[1].d_mem == 2); // expected-warning{{UNKNOWN}}
+  memset(array, 0, sizeof(array));
+  clang_analyzer_eval(array[1].b_mem == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(array[1].d_mem == 0); // expected-warning{{TRUE}}
+}
+
+void memset6_new_array_nonpod_object() {
+  Derived *array = new Derived[10];
+  clang_analyzer_eval(array[2].b_mem == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(array[2].d_mem == 2); // expected-warning{{UNKNOWN}}
+  memset(array, 0, 10 * sizeof(Derived));
+  clang_analyzer_eval(array[2].b_mem == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(array[2].d_mem == 0); // expected-warning{{TRUE}}
+  delete [] array;
+}
+
+void memset7_placement_new() {
+  Derived *d = new Derived();
+  clang_analyzer_eval(d->b_mem == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(d->d_mem == 2); // expected-warning{{TRUE}}
+
+  memset(d, 0, sizeof(Derived));
+  clang_analyzer_eval(d->b_mem == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(d->d_mem == 0); // expected-warning{{TRUE}}
+
+  Derived *d1 = new (d) Derived();
+  clang_analyzer_eval(d1->b_mem == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(d1->d_mem == 2); // expected-warning{{TRUE}}
+
+  memset(d1, 0, sizeof(Derived));
+  clang_analyzer_eval(d->b_mem == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(d->d_mem == 0); // expected-warning{{TRUE}}
+}
+
+class BaseVirtual {
+public:
+  int b_mem;
+  virtual int get() { return 1; }
+};
+
+class DerivedVirtual : public BaseVirtual {
+public:
+  int d_mem;
+};
+
+#ifdef SUPPRESS_OUT_OF_BOUND
+void memset8_virtual_inheritance_field() {
+  DerivedVirtual d;
+  memset(&d.b_mem, 0, sizeof(Derived));
+  clang_analyzer_eval(d.b_mem == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(d.d_mem == 0); // expected-warning{{UNKNOWN}}
+}
+#endif
+} // namespace memset_non_pod
+
+#ifdef SUPPRESS_OUT_OF_BOUND
+void memset1_new_array() {
+  int *array = new int[10];
+  memset(array, 0, 10 * sizeof(int));
+  clang_analyzer_eval(array[2] == 0); // expected-warning{{TRUE}}
+  memset(array + 1, 'a', 10 * sizeof(9));
+  clang_analyzer_eval(array[2] == 0); // expected-warning{{UNKNOWN}}
+  delete [] array;
+}
+#endif
Index: lib/StaticAnalyzer/Core/Store.cpp
===================================================================
--- lib/StaticAnalyzer/Core/Store.cpp
+++ lib/StaticAnalyzer/Core/Store.cpp
@@ -69,6 +69,10 @@
   return StoreRef(store, *this);
 }
 
+StoreRef StoreManager::OverwriteRegion(Store store, const MemRegion *R, SVal V) {
+  return StoreRef(store, *this); 
+}
+
 const ElementRegion *StoreManager::GetElementZeroRegion(const SubRegion *R,
                                                         QualType T) {
   NonLoc idx = svalBuilder.makeZeroArrayIndex();
Index: lib/StaticAnalyzer/Core/RegionStore.cpp
===================================================================
--- lib/StaticAnalyzer/Core/RegionStore.cpp
+++ lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -441,6 +441,16 @@
     return StoreRef(B.asImmutableMap().getRootWithoutRetain(), *this);
   }
 
+  // Clears out the specified region from the store and bind a new value with
+  // default binding.
+  StoreRef OverwriteRegion(Store store, const MemRegion *R, SVal V) override {
+    RegionBindingsRef B = getRegionBindings(store);
+    B = removeSubRegionBindings(B, cast<SubRegion>(R))
+            .addBinding(BindingKey::Make(R, BindingKey::Default), V);
+
+    return StoreRef(B.asImmutableMap().getRootWithoutRetain(), *this);
+  }
+
   /// Attempt to extract the fields of \p LCV and bind them to the struct region
   /// \p R.
   ///
@@ -1705,7 +1715,7 @@
         val.getAs<nonloc::CompoundVal>())
       return val;
 
-    llvm_unreachable("Unknown default value");
+    return val;
   }
 
   return None;
Index: lib/StaticAnalyzer/Core/ProgramState.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ProgramState.cpp
+++ lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -138,6 +138,18 @@
            new_state;
 }
 
+ProgramStateRef
+ProgramState::overwriteRegion(SVal Loc, SVal V,
+                              const LocationContext *LCtx) const {
+  ProgramStateManager &Mgr = getStateManager();
+  const MemRegion *R = Loc.castAs<loc::MemRegionVal>().getRegion();
+  const StoreRef &NewStore = Mgr.StoreMgr->OverwriteRegion(getStore(), R, V);
+  ProgramStateRef NewState = makeWithStore(NewStore);
+  return Mgr.getOwningEngine()
+             ? Mgr.getOwningEngine()->processRegionChange(NewState, R, LCtx)
+             : NewState;
+}
+
 typedef ArrayRef<const MemRegion *> RegionList;
 typedef ArrayRef<SVal> ValueList;
 
Index: lib/StaticAnalyzer/Checkers/CStringChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -2013,21 +2013,29 @@
   CurrentFunctionDescription = "memory set function";
 
   const Expr *Mem = CE->getArg(0);
+  const Expr *CharE = CE->getArg(1);
   const Expr *Size = CE->getArg(2);
+
   ProgramStateRef State = C.getState();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  ASTContext &Ctx = C.getASTContext();
+  QualType CmpType = svalBuilder.getConditionType();
 
   // See if the size argument is zero.
   const LocationContext *LCtx = C.getLocationContext();
   SVal SizeVal = State->getSVal(Size, LCtx);
   QualType SizeTy = Size->getType();
 
   ProgramStateRef StateZeroSize, StateNonZeroSize;
   std::tie(StateZeroSize, StateNonZeroSize) =
-    assumeZero(C, State, SizeVal, SizeTy);
+      assumeZero(C, State, SizeVal, SizeTy);
 
   // Get the value of the memory area.
   SVal MemVal = State->getSVal(Mem, LCtx);
 
+  // Get the value for writing.
+  SVal CharVal = State->getSVal(CharE, LCtx);
+
   // If the size is zero, there won't be any actual memory access, so
   // just bind the return value to the Mem buffer and return.
   if (StateZeroSize && !StateNonZeroSize) {
@@ -2045,11 +2053,79 @@
   State = CheckBufferAccess(C, State, Size, Mem);
   if (!State)
     return;
-  State = InvalidateBuffer(C, State, Mem, C.getSVal(Mem),
-                           /*IsSourceBuffer*/false, Size);
-  if (!State)
+
+  const MemRegion *MR = MemVal.getAsRegion();
+  if (!MR)
     return;
 
+  // Get the offset and the base region to figure out whether the offset of
+  // buffer is 0.
+  RegionOffset Offset = MR->getAsOffset();
+  const MemRegion *BR = Offset.getRegion();
+
+  Optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>();
+
+  // void *memset(void *dest, int ch, size_t count);
+  // For now we can only handle the case of offset is 0 and concrete char value.
+  if (Offset.isValid() && !Offset.hasSymbolicOffset() &&
+      Offset.getOffset() == 0 && CharVal.isConstant() && SizeNL) {
+    // Get the base region's extent.
+    auto *SubReg = cast<SubRegion>(BR);
+    DefinedOrUnknownSVal Extent = SubReg->getExtent(svalBuilder);
+
+    ProgramStateRef StateWholeReg, StateNotWholeReg;
+    std::tie(StateWholeReg, StateNotWholeReg) =
+        State->assume(svalBuilder.evalEQ(State, Extent, *SizeNL));
+
+    if (StateWholeReg && !StateNotWholeReg) {
+      // If the 'memset()' acts on the whole region of destination buffer,
+      // bind the second argument's value to the destination buffer with
+      // 'default binding'.
+      State = State->overwriteRegion(svalBuilder.makeLoc(BR), CharVal,
+                                     C.getLocationContext());
+    } else {
+      // If the destination buffer's extent is not equal to the value of
+      // third argument, just invalidate buffer.
+      //
+      // FIXME: This is a hack, 'InvalidateBuffer()' calls
+      // 'invalidateRegions()', which will remove the <MemRegion, SVal> pair
+      // in CStringLength map. So calls 'InvalidateBuffer()' after getting
+      // old string length and before setting the new string length.
+      State = InvalidateBuffer(C, State, Mem, C.getSVal(Mem),
+                               /*IsSourceBuffer*/ false, Size);
+    }
+
+    ProgramStateRef StateNullChar, StateNonNullChar;
+    std::tie(StateNullChar, StateNonNullChar) =
+        assumeZero(C, State, CharVal, Ctx.UnsignedCharTy);
+
+    if (StateNullChar && !StateNonNullChar) {
+      // If the value of the second arguement of 'memset()' is zero, set the
+      // string length of destination buffer to 0 directly.
+      State = setCStringLength(StateNullChar, MR,
+                               svalBuilder.makeZeroVal(Ctx.getSizeType()));
+    } else if (!StateNullChar && StateNonNullChar) {
+      SVal NewStrLen = svalBuilder.getMetadataSymbolVal(
+          CStringChecker::getTag(), MR, CE, Ctx.getSizeType(),
+          C.getLocationContext(), C.blockCount());
+
+      // If the value of second argument is not zero, then the string length
+      // is at least the size argument.
+      SVal NewStrLenGESize = svalBuilder.evalBinOp(StateNonNullChar, BO_GE,
+                                                   NewStrLen, SizeVal, CmpType);
+
+      State = setCStringLength(
+          StateNonNullChar->assume(
+              NewStrLenGESize.castAs<DefinedOrUnknownSVal>(), true),
+          MR, NewStrLen);
+    }
+  } else {
+    // If the offset is not zero and char value is not concrete, we can do
+    // nothing but invalidate the buffer.
+    State = InvalidateBuffer(C, State, Mem, C.getSVal(Mem),
+                             /*IsSourceBuffer*/ false, Size);
+  }
+
   State = State->BindExpr(CE, LCtx, MemVal);
   C.addTransition(State);
 }
Index: include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -109,6 +109,10 @@
 
   virtual StoreRef BindDefault(Store store, const MemRegion *R, SVal V);
 
+  // Clears out the specified region from the store and bind a new value with
+  // default binding.
+  virtual StoreRef OverwriteRegion(Store store, const MemRegion *R, SVal V);
+
   /// \brief Create a new store with the specified binding removed.
   /// \param ST the original store, that is the basis for the new store.
   /// \param L the location whose binding should be removed.
Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -244,6 +244,11 @@
 
   ProgramStateRef bindDefault(SVal loc, SVal V, const LocationContext *LCtx) const;
 
+  // Create a new state by invalidating the given region and binging the new
+  // value with default binding.
+  ProgramStateRef overwriteRegion(SVal Loc, SVal V,
+                                  const LocationContext *LCtx) const;
+
   ProgramStateRef killBinding(Loc LV) const;
 
   /// \brief Returns the state with bindings for the given regions
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to