diff options
Diffstat (limited to 'mrbgems/mruby-time/src')
| -rw-r--r-- | mrbgems/mruby-time/src/time.c | 75 |
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; |
