mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
Extract core part of gmtime_r, localtime_r (without logging)
This commit is contained in:
parent
b2d4e786b7
commit
bfb39164ce
@ -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);
|
||||
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;
|
||||
}
|
||||
#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);
|
||||
}
|
||||
#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);
|
||||
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;
|
||||
}
|
||||
#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);
|
||||
}
|
||||
#endif /* defined(HAVE_GMTIME_R) || ... */
|
||||
|
||||
#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK)
|
||||
#define HAVE_UNIX_MLOCKALL
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
193
src/lib/wallclock/tm_cvt.c
Normal file
193
src/lib/wallclock/tm_cvt.c
Normal file
@ -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) || ... */
|
17
src/lib/wallclock/tm_cvt.h
Normal file
17
src/lib/wallclock/tm_cvt.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user