summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-04-06 13:03:43 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-04-06 13:03:43 +0000
commit2bbeb4c0ad49847b1f73ba6281827bf513d05884 (patch)
tree0d2d7e914ea457f1940519b895053459f0a3689e
parent727371f88ac06fcb1e5417492f5ab17f5d58d886 (diff)
* configure.in: test localtime(3) overflow. [ruby-dev:40910]
* time.c (rb_gmtime_r): renamed from rb_gmtime. (rb_localtime_r): renamed from rb_localtime. (rb_localtime_r2): call rb_localtime_r and validate the result if there is overflow problem. (rb_gmtime_r2): call rb_gmtime_r and validate the result if there is overflow problem. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27237 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog11
-rw-r--r--configure.in42
-rw-r--r--time.c59
3 files changed, 98 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index b63951bcd0..a8a24d6216 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Tue Apr 6 21:55:25 2010 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: test localtime(3) overflow. [ruby-dev:40910]
+
+ * time.c (rb_gmtime_r): renamed from rb_gmtime.
+ (rb_localtime_r): renamed from rb_localtime.
+ (rb_localtime_r2): call rb_localtime_r and validate the result if
+ there is overflow problem.
+ (rb_gmtime_r2): call rb_gmtime_r and validate the result if there
+ is overflow problem.
+
Tue Apr 6 14:53:17 2010 NAKAMURA Usaku <usa@ruby-lang.org>
* include/ruby/win32.h: check definition existance before defining
diff --git a/configure.in b/configure.in
index 5047e9e054..27fbe56d98 100644
--- a/configure.in
+++ b/configure.in
@@ -1290,6 +1290,48 @@ if test "$rb_cv_negative_time_t" = yes; then
AC_DEFINE(NEGATIVE_TIME_T)
fi
+# [ruby-dev:40910] overflow of time on FreeBSD
+# http://www.freebsd.org/cgi/query-pr.cgi?pr=145341
+AC_CACHE_CHECK(for localtime(3) overflow correctly, rb_cv_localtime_overflow,
+ [AC_TRY_RUN([
+#include <time.h>
+
+void
+check(time_t t1)
+{
+ struct tm *tm;
+ time_t t2;
+ tm = localtime(&t1);
+ if (!tm)
+ return; /* overflow detected. ok. */
+ t2 = mktime(tm);
+ if (t1 == t2)
+ return; /* round-trip. ok. */
+ exit(1);
+}
+
+int
+main()
+{
+ time_t t;
+ if (~(time_t)0 <= 0) {
+ t = (((time_t)1) << (sizeof(time_t) * 8 - 2));
+ t |= t - 1;
+ }
+ else {
+ t = ~(time_t)0;
+ }
+ check(t);
+ return 0;
+}
+],
+ rb_cv_localtime_overflow=yes,
+ rb_cv_localtime_overflow=no,
+ rb_cv_localtime_overflow=yes)])
+if test "$rb_cv_localtime_overflow" = no; then
+ AC_DEFINE(LOCALTIME_OVERFLOW_PROBLEM)
+fi
+
if test "$ac_cv_func_sigprocmask" = yes && test "$ac_cv_func_sigaction" = yes; then
AC_DEFINE(POSIX_SIGNAL)
else
diff --git a/time.c b/time.c
index d43165ec55..08d4199fdb 100644
--- a/time.c
+++ b/time.c
@@ -840,33 +840,64 @@ static int leap_year_p(long y);
#define leap_year_v_p(y) leap_year_p(NUM2LONG(mod(v, INT2FIX(400))))
#ifdef HAVE_GMTIME_R
-#define IF_HAVE_GMTIME_R(x) x
-#define ASCTIME(tm, buf) asctime_r((tm), (buf))
-#define GMTIME(tm, result) gmtime_r((tm), &(result))
-#define LOCALTIME(tm, result) (tzset(),localtime_r((tm), &(result)))
+#define rb_gmtime_r(t, tm) gmtime_r(t, tm)
+#define rb_localtime_r(t, tm) localtime_r(t, tm)
#else
-#define IF_HAVE_GMTIME_R(x) /* nothing */
-#define ASCTIME(tm, buf) asctime(tm)
-#define GMTIME(tm, result) rb_gmtime((tm), &(result))
-#define LOCALTIME(tm, result) rb_localtime((tm), &(result))
-
static inline struct tm *
-rb_gmtime(const time_t *tm, struct tm *result)
+rb_gmtime_r(const time_t *tp, struct tm *result)
{
- struct tm *t = gmtime(tm);
+ struct tm *t = gmtime(tp);
if (t) *result = *t;
return t;
}
static inline struct tm *
-rb_localtime(const time_t *tm, struct tm *result)
+rb_localtime_r(const time_t *tp, struct tm *result)
{
- struct tm *t = localtime(tm);
+ struct tm *t = localtime(tp);
if (t) *result = *t;
return t;
}
#endif
+static struct tm *
+rb_localtime_r2(const time_t *t, struct tm *result)
+{
+ result = rb_localtime_r(t, result);
+#if defined(HAVE_MKTIME) && defined(LOCALTIME_OVERFLOW_PROBLEM)
+ if (result) {
+ time_t t2 = mktime(result);
+ if (*t != t2)
+ result = NULL;
+ }
+#endif
+ return result;
+}
+#define LOCALTIME(tm, result) (tzset(),rb_localtime_r2((tm), &(result)))
+
+#if !defined(HAVE_STRUCT_TM_TM_GMTOFF)
+ static struct tm *
+ rb_gmtime_r2(const time_t *t, struct tm *result)
+ {
+ result = rb_gmtime_r(t, result);
+#if defined(HAVE_TIMEGM) && defined(LOCALTIME_OVERFLOW_PROBLEM)
+ if (result) {
+ time_t t2 = timegm(result);
+ if (*t != t2)
+ result = NULL;
+ }
+#endif
+ return result;
+ }
+# define GMTIME(tm, result) rb_gmtime_r2((tm), &(result))
+#endif
+
+#ifdef HAVE_GMTIME_R
+#define ASCTIME(tm, buf) asctime_r((tm), (buf))
+#else
+#define ASCTIME(tm, buf) asctime(tm)
+#endif
+
static const int common_year_yday_offset[] = {
-1,
-1 + 31,
@@ -1085,7 +1116,7 @@ gmtime_with_leapsecond(const time_t *timep, struct tm *result)
int sign;
int gmtoff_sec, gmtoff_min, gmtoff_hour, gmtoff_day;
long gmtoff;
- t = localtime_r(timep, result);
+ t = LOCALTIME(timep, *result);
if (t == NULL)
return NULL;