[sanitizer] Fix handling of edge cases in mbstowcs-like interceptors.


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@186002 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index b73e35c..82da50e 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -1230,6 +1230,8 @@
   EXPECT_EQ(buff[0], 'a');
   EXPECT_EQ(buff[1], 'b');
   EXPECT_EQ(buff[2], 'c');
+  EXPECT_EQ(buff[3], '\0');
+  EXPECT_POISONED(buff[4]);
 }
 
 TEST(MemorySanitizer, wcsnrtombs) {
@@ -1241,7 +1243,7 @@
   EXPECT_EQ(res, 2);
   EXPECT_EQ(buff[0], 'a');
   EXPECT_EQ(buff[1], 'b');
-  EXPECT_EQ(buff[2], 0);
+  EXPECT_POISONED(buff[2]);
 }
 
 TEST(MemorySanitizer, mbtowc) {
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 67864c5..7899204 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -1542,8 +1542,10 @@
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len);
   SIZE_T res = REAL(mbstowcs)(dest, src, len);
-  if (res != (SIZE_T) - 1 && dest)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, (res + 1) * sizeof(wchar_t));
+  if (res != (SIZE_T) - 1 && dest) {
+    SIZE_T write_cnt = res + (res < len);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+  }
   return res;
 }
 
@@ -1555,8 +1557,12 @@
     COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
   }
   SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps);
-  if (res != (SIZE_T) - 1 && dest)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, (res + 1) * sizeof(wchar_t));
+  if (res != (SIZE_T)(-1) && dest && src) {
+    // This function, and several others, may or may not write the terminating
+    // \0 character. They write it iff they clear *src.
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+  }
   return res;
 }
 
@@ -1577,8 +1583,10 @@
     if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
   }
   SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps);
-  if (res != (SIZE_T) - 1 && dest)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, (res + 1) * sizeof(wchar_t));
+  if (res != (SIZE_T)(-1) && dest && src) {
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+  }
   return res;
 }
 
@@ -1592,8 +1600,10 @@
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len);
   SIZE_T res = REAL(wcstombs)(dest, src, len);
-  if (res != (SIZE_T) - 1 && dest)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res + 1);
+  if (res != (SIZE_T) - 1 && dest) {
+    SIZE_T write_cnt = res + (res < len);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
   return res;
 }
 
@@ -1605,8 +1615,10 @@
     COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
   }
   SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps);
-  if (res != (SIZE_T) - 1 && dest)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res + 1);
+  if (res != (SIZE_T) - 1 && dest && src) {
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
   return res;
 }
 
@@ -1627,8 +1639,10 @@
     if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
   }
   SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps);
-  if (res != (SIZE_T) - 1 && dest)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res + 1);
+  if (res != (SIZE_T) - 1 && dest && src) {
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
   return res;
 }