[tor-commits] [tor/master] Extract core part of gmtime_r, localtime_r (without logging)

nickm at torproject.org nickm at torproject.org
Tue Jun 26 15:27:41 UTC 2018


commit bfb39164ce49450fad11611a129dd875acebde54
Author: Nick Mathewson <nickm at torproject.org>
Date:   Fri Jun 22 11:07:10 2018 -0400

    Extract core part of gmtime_r, localtime_r (without logging)
---
 src/common/compat.c          | 172 ++++----------------------------------
 src/lib/log/torlog.c         |   4 +-
 src/lib/wallclock/include.am |   2 +
 src/lib/wallclock/tm_cvt.c   | 193 +++++++++++++++++++++++++++++++++++++++++++
 src/lib/wallclock/tm_cvt.h   |  17 ++++
 5 files changed, 230 insertions(+), 158 deletions(-)

diff --git a/src/common/compat.c b/src/common/compat.c
index b4175c15a..351fa0563 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -127,6 +127,7 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
 #include "lib/log/torlog.h"
 #include "common/util.h"
 #include "lib/container/smartlist.h"
+#include "lib/wallclock/tm_cvt.h"
 #include "common/address.h"
 #include "common/sandbox.h"
 
@@ -2648,183 +2649,40 @@ compute_num_cpus(void)
   return num_cpus;
 }
 
-#if !defined(_WIN32)
-/** Defined iff we need to add locks when defining fake versions of reentrant
- * versions of time-related functions. */
-#define TIME_FNS_NEED_LOCKS
-#endif
-
-/** Helper: Deal with confused or out-of-bounds values from localtime_r and
- * friends.  (On some platforms, they can give out-of-bounds values or can
- * return NULL.)  If <b>islocal</b>, this is a localtime result; otherwise
- * it's from gmtime.  The function returns <b>r</b>, when given <b>timep</b>
- * as its input. If we need to store new results, store them in
- * <b>resultbuf</b>. */
-static struct tm *
-correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
-           struct tm *r)
-{
-  const char *outcome;
-
-  if (PREDICT_LIKELY(r)) {
-    /* We can't strftime dates after 9999 CE, and we want to avoid dates
-     * before 1 CE (avoiding the year 0 issue and negative years). */
-    if (r->tm_year > 8099) {
-      r->tm_year = 8099;
-      r->tm_mon = 11;
-      r->tm_mday = 31;
-      r->tm_yday = 364;
-      r->tm_wday = 6;
-      r->tm_hour = 23;
-      r->tm_min = 59;
-      r->tm_sec = 59;
-    } else if (r->tm_year < (1-1900)) {
-      r->tm_year = (1-1900);
-      r->tm_mon = 0;
-      r->tm_mday = 1;
-      r->tm_yday = 0;
-      r->tm_wday = 0;
-      r->tm_hour = 0;
-      r->tm_min = 0;
-      r->tm_sec = 0;
-    }
-    return r;
-  }
-
-  /* If we get here, gmtime or localtime returned NULL. It might have done
-   * this because of overrun or underrun, or it might have done it because of
-   * some other weird issue. */
-  if (timep) {
-    if (*timep < 0) {
-      r = resultbuf;
-      r->tm_year = 70; /* 1970 CE */
-      r->tm_mon = 0;
-      r->tm_mday = 1;
-      r->tm_yday = 0;
-      r->tm_wday = 0;
-      r->tm_hour = 0;
-      r->tm_min = 0 ;
-      r->tm_sec = 0;
-      outcome = "Rounding up to 1970";
-      goto done;
-    } else if (*timep >= INT32_MAX) {
-      /* Rounding down to INT32_MAX isn't so great, but keep in mind that we
-       * only do it if gmtime/localtime tells us NULL. */
-      r = resultbuf;
-      r->tm_year = 137; /* 2037 CE */
-      r->tm_mon = 11;
-      r->tm_mday = 31;
-      r->tm_yday = 364;
-      r->tm_wday = 6;
-      r->tm_hour = 23;
-      r->tm_min = 59;
-      r->tm_sec = 59;
-      outcome = "Rounding down to 2037";
-      goto done;
-    }
-  }
-
-  /* If we get here, then gmtime/localtime failed without getting an extreme
-   * value for *timep */
-  /* LCOV_EXCL_START */
-  tor_fragile_assert();
-  r = resultbuf;
-  memset(resultbuf, 0, sizeof(struct tm));
-  outcome="can't recover";
-  /* LCOV_EXCL_STOP */
- done:
-  log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s",
-           islocal?"localtime":"gmtime",
-           timep?I64_PRINTF_ARG(*timep):0,
-           strerror(errno),
-           outcome);
-  return r;
-}
 
-/** @{ */
 /** As localtime_r, but defined for platforms that don't have it:
  *
  * Convert *<b>timep</b> to a struct tm in local time, and store the value in
  * *<b>result</b>.  Return the result on success, or NULL on failure.
  */
-#ifdef HAVE_LOCALTIME_R
 struct tm *
 tor_localtime_r(const time_t *timep, struct tm *result)
 {
-  struct tm *r;
-  r = localtime_r(timep, result);
-  return correct_tm(1, timep, result, r);
-}
-#elif defined(TIME_FNS_NEED_LOCKS)
-struct tm *
-tor_localtime_r(const time_t *timep, struct tm *result)
-{
-  struct tm *r;
-  static tor_mutex_t *m=NULL;
-  if (!m) { m=tor_mutex_new(); }
-  tor_assert(result);
-  tor_mutex_acquire(m);
-  r = localtime(timep);
-  if (r)
-    memcpy(result, r, sizeof(struct tm));
-  tor_mutex_release(m);
-  return correct_tm(1, timep, result, r);
-}
-#else
-struct tm *
-tor_localtime_r(const time_t *timep, struct tm *result)
-{
-  struct tm *r;
-  tor_assert(result);
-  r = localtime(timep);
-  if (r)
-    memcpy(result, r, sizeof(struct tm));
-  return correct_tm(1, timep, result, r);
+  char *err = NULL;
+  struct tm *r = tor_localtime_r_msg(timep, result, &err);
+  if (err) {
+    log_warn(LD_BUG, "%s", err);
+    tor_free(err);
+  }
+  return r;
 }
-#endif /* defined(HAVE_LOCALTIME_R) || ... */
-/** @} */
 
-/** @{ */
 /** As gmtime_r, but defined for platforms that don't have it:
  *
  * Convert *<b>timep</b> to a struct tm in UTC, and store the value in
  * *<b>result</b>.  Return the result on success, or NULL on failure.
  */
-#ifdef HAVE_GMTIME_R
 struct tm *
 tor_gmtime_r(const time_t *timep, struct tm *result)
 {
-  struct tm *r;
-  r = gmtime_r(timep, result);
-  return correct_tm(0, timep, result, r);
-}
-#elif defined(TIME_FNS_NEED_LOCKS)
-struct tm *
-tor_gmtime_r(const time_t *timep, struct tm *result)
-{
-  struct tm *r;
-  static tor_mutex_t *m=NULL;
-  if (!m) { m=tor_mutex_new(); }
-  tor_assert(result);
-  tor_mutex_acquire(m);
-  r = gmtime(timep);
-  if (r)
-    memcpy(result, r, sizeof(struct tm));
-  tor_mutex_release(m);
-  return correct_tm(0, timep, result, r);
-}
-#else
-struct tm *
-tor_gmtime_r(const time_t *timep, struct tm *result)
-{
-  struct tm *r;
-  tor_assert(result);
-  r = gmtime(timep);
-  if (r)
-    memcpy(result, r, sizeof(struct tm));
-  return correct_tm(0, timep, result, r);
+  char *err = NULL;
+  struct tm *r = tor_gmtime_r_msg(timep, result, &err);
+  if (err) {
+    log_warn(LD_BUG, "%s", err);
+    tor_free(err);
+  }
+  return r;
 }
-#endif /* defined(HAVE_GMTIME_R) || ... */
 
 #if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK)
 #define HAVE_UNIX_MLOCKALL
diff --git a/src/lib/log/torlog.c b/src/lib/log/torlog.c
index aec469c53..fc2f898d8 100644
--- a/src/lib/log/torlog.c
+++ b/src/lib/log/torlog.c
@@ -41,6 +41,7 @@
 #include "lib/string/util_string.h"
 #include "lib/wallclock/tor_gettimeofday.h"
 #include "lib/wallclock/approx_time.h"
+#include "lib/wallclock/tm_cvt.h"
 
 #ifdef HAVE_ANDROID_LOG_H
 #include <android/log.h>
@@ -298,7 +299,8 @@ log_prefix_(char *buf, size_t buf_len, int severity)
     ms -= ((int)now.tv_usec / 1000) % log_time_granularity;
   }
 
-  n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm));
+  n = strftime(buf, buf_len, "%b %d %H:%M:%S",
+               tor_localtime_r_msg(&t, &tm, NULL));
   r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ", ms,
                    sev_to_string(severity));
 
diff --git a/src/lib/wallclock/include.am b/src/lib/wallclock/include.am
index d414eb468..7b735e97e 100644
--- a/src/lib/wallclock/include.am
+++ b/src/lib/wallclock/include.am
@@ -7,6 +7,7 @@ endif
 
 src_lib_libtor_wallclock_a_SOURCES =			\
 	src/lib/wallclock/approx_time.c			\
+	src/lib/wallclock/tm_cvt.c			\
 	src/lib/wallclock/tor_gettimeofday.c
 
 src_lib_libtor_wallclock_testing_a_SOURCES = \
@@ -16,4 +17,5 @@ src_lib_libtor_wallclock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 
 noinst_HEADERS +=					\
 	src/lib/wallclock/approx_time.h			\
+	src/lib/wallclock/tm_cvt.h			\
 	src/lib/wallclock/tor_gettimeofday.h
diff --git a/src/lib/wallclock/tm_cvt.c b/src/lib/wallclock/tm_cvt.c
new file mode 100644
index 000000000..bb23d1bef
--- /dev/null
+++ b/src/lib/wallclock/tm_cvt.c
@@ -0,0 +1,193 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "lib/cc/torint.h"
+#include "lib/cc/compat_compiler.h"
+#include "lib/wallclock/tm_cvt.h"
+#include "lib/string/printf.h"
+
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+
+#if !defined(_WIN32)
+/** Defined iff we need to add locks when defining fake versions of reentrant
+ * versions of time-related functions. */
+#define TIME_FNS_NEED_LOCKS
+#endif
+
+/** Helper: Deal with confused or out-of-bounds values from localtime_r and
+ * friends.  (On some platforms, they can give out-of-bounds values or can
+ * return NULL.)  If <b>islocal</b>, this is a localtime result; otherwise
+ * it's from gmtime.  The function returns <b>r</b>, when given <b>timep</b>
+ * as its input. If we need to store new results, store them in
+ * <b>resultbuf</b>. */
+static struct tm *
+correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
+           struct tm *r, char **err_out)
+{
+  const char *outcome;
+
+  if (PREDICT_LIKELY(r)) {
+    /* We can't strftime dates after 9999 CE, and we want to avoid dates
+     * before 1 CE (avoiding the year 0 issue and negative years). */
+    if (r->tm_year > 8099) {
+      r->tm_year = 8099;
+      r->tm_mon = 11;
+      r->tm_mday = 31;
+      r->tm_yday = 364;
+      r->tm_wday = 6;
+      r->tm_hour = 23;
+      r->tm_min = 59;
+      r->tm_sec = 59;
+    } else if (r->tm_year < (1-1900)) {
+      r->tm_year = (1-1900);
+      r->tm_mon = 0;
+      r->tm_mday = 1;
+      r->tm_yday = 0;
+      r->tm_wday = 0;
+      r->tm_hour = 0;
+      r->tm_min = 0;
+      r->tm_sec = 0;
+    }
+    return r;
+  }
+
+  /* If we get here, gmtime or localtime returned NULL. It might have done
+   * this because of overrun or underrun, or it might have done it because of
+   * some other weird issue. */
+  if (timep) {
+    if (*timep < 0) {
+      r = resultbuf;
+      r->tm_year = 70; /* 1970 CE */
+      r->tm_mon = 0;
+      r->tm_mday = 1;
+      r->tm_yday = 0;
+      r->tm_wday = 0;
+      r->tm_hour = 0;
+      r->tm_min = 0 ;
+      r->tm_sec = 0;
+      outcome = "Rounding up to 1970";
+      goto done;
+    } else if (*timep >= INT32_MAX) {
+      /* Rounding down to INT32_MAX isn't so great, but keep in mind that we
+       * only do it if gmtime/localtime tells us NULL. */
+      r = resultbuf;
+      r->tm_year = 137; /* 2037 CE */
+      r->tm_mon = 11;
+      r->tm_mday = 31;
+      r->tm_yday = 364;
+      r->tm_wday = 6;
+      r->tm_hour = 23;
+      r->tm_min = 59;
+      r->tm_sec = 59;
+      outcome = "Rounding down to 2037";
+      goto done;
+    }
+  }
+
+  /* If we get here, then gmtime/localtime failed without getting an extreme
+   * value for *timep */
+  /* LCOV_EXCL_START */
+  r = resultbuf;
+  memset(resultbuf, 0, sizeof(struct tm));
+  outcome="can't recover";
+  /* LCOV_EXCL_STOP */
+ done:
+  if (err_out) {
+    tor_asprintf(err_out, "%s("I64_FORMAT") failed with error %s: %s",
+                 islocal?"localtime":"gmtime",
+                 timep?I64_PRINTF_ARG(*timep):0,
+                 strerror(errno),
+                 outcome);
+  }
+  return r;
+}
+
+/** @{ */
+/** As localtime_r, but defined for platforms that don't have it:
+ *
+ * Convert *<b>timep</b> to a struct tm in local time, and store the value in
+ * *<b>result</b>.  Return the result on success, or NULL on failure.
+ */
+#ifdef HAVE_LOCALTIME_R
+struct tm *
+tor_localtime_r_msg(const time_t *timep, struct tm *result, char **err_out)
+{
+  struct tm *r;
+  r = localtime_r(timep, result);
+  return correct_tm(1, timep, result, r, err_out);
+}
+#elif defined(TIME_FNS_NEED_LOCKS)
+struct tm *
+tor_localtime_r_msg(const time_t *timep, struct tm *result, char **err_out)
+{
+  struct tm *r;
+  static tor_mutex_t *m=NULL;
+  if (!m) { m=tor_mutex_new(); }
+  raw_assert(result);
+  tor_mutex_acquire(m);
+  r = localtime(timep);
+  if (r)
+    memcpy(result, r, sizeof(struct tm));
+  tor_mutex_release(m);
+  return correct_tm(1, timep, result, r, err_out);
+}
+#else
+struct tm *
+tor_localtime_r_msg(const time_t *timep, struct tm *result, char **err_out)
+{
+  struct tm *r;
+  raw_assert(result);
+  r = localtime(timep);
+  if (r)
+    memcpy(result, r, sizeof(struct tm));
+  return correct_tm(1, timep, result, rm, err_out);
+}
+#endif /* defined(HAVE_LOCALTIME_R) || ... */
+/** @} */
+
+/** @{ */
+/** As gmtime_r, but defined for platforms that don't have it:
+ *
+ * Convert *<b>timep</b> to a struct tm in UTC, and store the value in
+ * *<b>result</b>.  Return the result on success, or NULL on failure.
+ */
+#ifdef HAVE_GMTIME_R
+struct tm *
+tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out)
+{
+  struct tm *r;
+  r = gmtime_r(timep, result);
+  return correct_tm(0, timep, result, r, err_out);
+}
+#elif defined(TIME_FNS_NEED_LOCKS)
+struct tm *
+tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out)
+{
+  struct tm *r;
+  static tor_mutex_t *m=NULL;
+  if (!m) { m=tor_mutex_new(); }
+  raw_assert(result);
+  tor_mutex_acquire(m);
+  r = gmtime(timep);
+  if (r)
+    memcpy(result, r, sizeof(struct tm));
+  tor_mutex_release(m);
+  return correct_tm(0, timep, result, r, err_out);
+}
+#else
+struct tm *
+tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out)
+{
+  struct tm *r;
+  raw_assert(result);
+  r = gmtime(timep);
+  if (r)
+    memcpy(result, r, sizeof(struct tm));
+  return correct_tm(0, timep, result, r, err_out);
+}
+#endif /* defined(HAVE_GMTIME_R) || ... */
diff --git a/src/lib/wallclock/tm_cvt.h b/src/lib/wallclock/tm_cvt.h
new file mode 100644
index 000000000..4d87acd4f
--- /dev/null
+++ b/src/lib/wallclock/tm_cvt.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_WALLCLOCK_TM_CVT_H
+#define TOR_WALLCLOCK_TM_CVT_H
+
+#include <sys/types.h>
+
+struct tm;
+struct tm *tor_localtime_r_msg(const time_t *timep, struct tm *result,
+                               char **err_out);
+struct tm *tor_gmtime_r_msg(const time_t *timep, struct tm *result,
+                            char **err_out);
+
+#endif





More information about the tor-commits mailing list