summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-time/src
diff options
context:
space:
mode:
Diffstat (limited to 'mrbgems/mruby-time/src')
-rw-r--r--mrbgems/mruby-time/src/time.c75
1 files changed, 61 insertions, 14 deletions
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c
index 702cf2e29..dc8a8ef22 100644
--- a/mrbgems/mruby-time/src/time.c
+++ b/mrbgems/mruby-time/src/time.c
@@ -21,6 +21,9 @@
#endif
#include <stdlib.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
#define NDIV(x,y) (-(-((x)+1)/(y))-1)
#define TO_S_FMT "%Y-%m-%d %H:%M:%S "
@@ -214,7 +217,7 @@ typedef mrb_int mrb_sec;
MRB_TIME_T_UINT ? 0 : \
(sizeof(time_t) <= 4 ? INT32_MIN : INT64_MIN) \
)
-#define MRB_TIME_MAX ( \
+#define MRB_TIME_MAX (time_t)( \
MRB_TIME_T_UINT ? (sizeof(time_t) <= 4 ? UINT32_MAX : UINT64_MAX) : \
(sizeof(time_t) <= 4 ? INT32_MAX : INT64_MAX) \
)
@@ -376,9 +379,14 @@ current_mrb_time(mrb_state *mrb)
#if defined(TIME_UTC) && !defined(__ANDROID__)
{
struct timespec ts;
- if (timespec_get(&ts, TIME_UTC) == 0) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "timespec_get() failed for unknown reasons");
- }
+ timespec_get(&ts, TIME_UTC);
+ sec = ts.tv_sec;
+ usec = ts.tv_nsec / 1000;
+ }
+#elif (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(_POSIX_MONOTONIC_CLOCK)
+ {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
sec = ts.tv_sec;
usec = ts.tv_nsec / 1000;
}
@@ -463,7 +471,7 @@ time_mktime(mrb_state *mrb, mrb_int ayear, mrb_int amonth, mrb_int aday,
|| (nowtime.tm_hour == 24 && (nowtime.tm_min > 0 || nowtime.tm_sec > 0))
|| nowtime.tm_min < 0 || nowtime.tm_min > 59
|| nowtime.tm_sec < 0 || nowtime.tm_sec > 60)
- mrb_raise(mrb, E_RUNTIME_ERROR, "argument out of range");
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "argument out of range");
if (timezone == MRB_TIMEZONE_UTC) {
nowsecs = timegm(&nowtime);
@@ -472,7 +480,7 @@ time_mktime(mrb_state *mrb, mrb_int ayear, mrb_int amonth, mrb_int aday,
nowsecs = mktime(&nowtime);
}
if (nowsecs == (time_t)-1) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time.");
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time");
}
return time_alloc_time(mrb, nowsecs, ausec, timezone);
@@ -556,6 +564,12 @@ mrb_time_cmp(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(0);
}
+static mrb_noreturn void
+int_overflow(mrb_state *mrb, const char *reason)
+{
+ mrb_raisef(mrb, E_RANGE_ERROR, "time_t overflow in Time %s", reason);
+}
+
static mrb_value
mrb_time_plus(mrb_state *mrb, mrb_value self)
{
@@ -565,7 +579,24 @@ mrb_time_plus(mrb_state *mrb, mrb_value self)
tm = time_get_ptr(mrb, self);
sec = mrb_to_time_t(mrb, o, &usec);
- return mrb_time_make_time(mrb, mrb_obj_class(mrb, self), tm->sec+sec, tm->usec+usec, tm->timezone);
+#ifdef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
+ if (__builtin_add_overflow(tm->sec, sec, &sec)) {
+ int_overflow(mrb, "addition");
+ }
+#else
+ if (sec >= 0) {
+ if (tm->sec > MRB_TIME_MAX - sec) {
+ int_overflow(mrb, "addition");
+ }
+ }
+ else {
+ if (tm->sec < MRB_TIME_MIN - sec) {
+ int_overflow(mrb, "addition");
+ }
+ }
+ sec = tm->sec + sec;
+#endif
+ return mrb_time_make_time(mrb, mrb_obj_class(mrb, self), sec, tm->usec+usec, tm->timezone);
}
static mrb_value
@@ -592,7 +623,24 @@ mrb_time_minus(mrb_state *mrb, mrb_value self)
else {
time_t sec, usec;
sec = mrb_to_time_t(mrb, other, &usec);
- return mrb_time_make_time(mrb, mrb_obj_class(mrb, self), tm->sec-sec, tm->usec-usec, tm->timezone);
+#ifdef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
+ if (__builtin_sub_overflow(tm->sec, sec, &sec)) {
+ int_overflow(mrb, "subtraction");
+ }
+#else
+ if (sec >= 0) {
+ if (tm->sec < MRB_TIME_MIN + sec) {
+ int_overflow(mrb, "subtraction");
+ }
+ }
+ else {
+ if (tm->sec > MRB_TIME_MAX + sec) {
+ int_overflow(mrb, "subtraction");
+ }
+ }
+ sec = tm->sec - sec;
+#endif
+ return mrb_time_make_time(mrb, mrb_obj_class(mrb, self), sec, tm->usec-usec, tm->timezone);
}
}
@@ -654,16 +702,15 @@ mrb_time_asctime(mrb_state *mrb, mrb_value self)
int len;
#if defined(MRB_NO_STDIO)
- char *s;
# ifdef NO_ASCTIME_R
- s = asctime(d);
+ char *buf = asctime(d);
# else
- char buf[32];
+ char buf[32], *s;
s = asctime_r(d, buf);
# endif
- len = strlen(s)-1; /* truncate the last newline */
+ len = strlen(buf)-1; /* truncate the last newline */
#else
- char buf[256];
+ char buf[32];
len = snprintf(buf, sizeof(buf), "%s %s %2d %02d:%02d:%02d %.4d",
wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday,
@@ -928,7 +975,7 @@ time_to_s_local(mrb_state *mrb, struct mrb_time *tm, char *buf, size_t buf_len)
int offset;
if (utc_sec == (time_t)-1) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time.");
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time");
}
offset = abs((int)(utc_sec - tm->sec) / 60);
datetime.tm_year = 100;