[sanitizer] Fix localtime and gmtime interceptors to clean tm->tm_zone.


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@191827 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index 2f9c72e..c28f79b 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -1517,6 +1517,7 @@
   EXPECT_NOT_POISONED(time->tm_hour);
   EXPECT_NOT_POISONED(time->tm_year);
   EXPECT_NOT_POISONED(time->tm_isdst);
+  EXPECT_NE(0, strlen(time->tm_zone));
 }
 
 TEST(MemorySanitizer, localtime_r) {
@@ -1528,6 +1529,7 @@
   EXPECT_NOT_POISONED(time.tm_hour);
   EXPECT_NOT_POISONED(time.tm_year);
   EXPECT_NOT_POISONED(time.tm_isdst);
+  EXPECT_NE(0, strlen(time.tm_zone));
 }
 
 TEST(MemorySanitizer, mmap) {
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 4b966d7..4be40b7 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -403,43 +403,50 @@
 
 
 #if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
-INTERCEPTOR(void *, localtime, unsigned long *timep) {
+static void unpoison_tm(void *ctx, __sanitizer_tm *tm) {
+  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+  if (tm->tm_zone)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm->tm_zone,
+                                   REAL(strlen(tm->tm_zone)) + 1);
+}
+
+INTERCEPTOR(__sanitizer_tm *, localtime, unsigned long *timep) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep);
-  void *res = REAL(localtime)(timep);
+  __sanitizer_tm *res = REAL(localtime)(timep);
   if (res) {
     COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+    unpoison_tm(ctx, res);
   }
   return res;
 }
-INTERCEPTOR(void *, localtime_r, unsigned long *timep, void *result) {
+INTERCEPTOR(__sanitizer_tm *, localtime_r, unsigned long *timep, void *result) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result);
-  void *res = REAL(localtime_r)(timep, result);
+  __sanitizer_tm *res = REAL(localtime_r)(timep, result);
   if (res) {
     COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+    unpoison_tm(ctx, res);
   }
   return res;
 }
-INTERCEPTOR(void *, gmtime, unsigned long *timep) {
+INTERCEPTOR(__sanitizer_tm *, gmtime, unsigned long *timep) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep);
-  void *res = REAL(gmtime)(timep);
+  __sanitizer_tm *res = REAL(gmtime)(timep);
   if (res) {
     COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+    unpoison_tm(ctx, res);
   }
   return res;
 }
-INTERCEPTOR(void *, gmtime_r, unsigned long *timep, void *result) {
+INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result);
-  void *res = REAL(gmtime_r)(timep, result);
+  __sanitizer_tm *res = REAL(gmtime_r)(timep, result);
   if (res) {
     COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+    unpoison_tm(ctx, res);
   }
   return res;
 }
@@ -463,22 +470,22 @@
   }
   return res;
 }
-INTERCEPTOR(char *, asctime, void *tm) {
+INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm);
   char *res = REAL(asctime)(tm);
   if (res) {
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
   }
   return res;
 }
-INTERCEPTOR(char *, asctime_r, void *tm, char *result) {
+INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result);
   char *res = REAL(asctime_r)(tm, result);
   if (res) {
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
   }
   return res;
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index bcf2c0a..9cc975a 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -882,4 +882,17 @@
 CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs);
 #endif
 
+CHECK_TYPE_SIZE(tm);
+CHECK_SIZE_AND_OFFSET(tm, tm_sec);
+CHECK_SIZE_AND_OFFSET(tm, tm_min);
+CHECK_SIZE_AND_OFFSET(tm, tm_hour);
+CHECK_SIZE_AND_OFFSET(tm, tm_mday);
+CHECK_SIZE_AND_OFFSET(tm, tm_mon);
+CHECK_SIZE_AND_OFFSET(tm, tm_year);
+CHECK_SIZE_AND_OFFSET(tm, tm_wday);
+CHECK_SIZE_AND_OFFSET(tm, tm_yday);
+CHECK_SIZE_AND_OFFSET(tm, tm_isdst);
+CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff);
+CHECK_SIZE_AND_OFFSET(tm, tm_zone);
+
 #endif  // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 2893ca7..f9573d4 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -22,7 +22,6 @@
   extern unsigned struct_stat_sz;
   extern unsigned struct_stat64_sz;
   extern unsigned struct_rusage_sz;
-  extern unsigned struct_tm_sz;
   extern unsigned struct_passwd_sz;
   extern unsigned struct_group_sz;
   extern unsigned siginfo_t_sz;
@@ -96,6 +95,20 @@
   typedef unsigned __sanitizer_pthread_key_t;
 #endif
 
+  struct __sanitizer_tm {
+    int tm_sec;
+    int tm_min;
+    int tm_hour;
+    int tm_mday;
+    int tm_mon;
+    int tm_year;
+    int tm_wday;
+    int tm_yday;
+    int tm_isdst;
+    long int tm_gmtoff;
+    const char *tm_zone;
+  };
+
 #if SANITIZER_ANDROID || SANITIZER_MAC
   struct __sanitizer_msghdr {
     void *msg_name;