From 857de450366f8f52df610f3075ae10b1ee3fe848 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 24 Nov 2025 08:06:40 +0900 Subject: [PATCH] mruby-time: normalize microseconds before converting to nanoseconds when converting microseconds to nanoseconds, multiplying very large usec values by 1000 can cause signed integer overflow. for example, Time.at(0, 9999999999990768) would trigger ASAN runtime error. fixed by normalizing microseconds >= 1000000 (or <= -1000000) to seconds before the multiplication, preventing overflow while maintaining correct time representation. this normalization converts excess microseconds to seconds, leaving only the fractional part for multiplication. applied fix to both time_alloc() and mrb_time_at() functions. Co-authored-by: Claude --- mrbgems/mruby-time/src/time.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index f6f9353fb..e47c58048 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -485,11 +485,20 @@ static struct mrb_time* time_alloc(mrb_state *mrb, mrb_value sec, mrb_value usec, enum mrb_timezone timezone) { time_t tsec, tusec; /* Variables to hold converted seconds and microseconds */ + time_t nsec; tsec = mrb_to_time_t(mrb, sec, &tusec); tusec += mrb_to_time_t(mrb, usec, NULL); - return time_alloc_time(mrb, tsec, tusec * NSECS_PER_USEC, timezone); + /* Normalize microseconds to avoid overflow when converting to nanoseconds */ + if (tusec >= USECS_PER_SEC || tusec <= -USECS_PER_SEC) { + time_t sec_adjustment = tusec / USECS_PER_SEC; + tusec -= sec_adjustment * USECS_PER_SEC; + tsec += sec_adjustment; + } + + nsec = tusec * NSECS_PER_USEC; + return time_alloc_time(mrb, tsec, nsec, timezone); } /* @@ -596,7 +605,17 @@ time_now(mrb_state *mrb, mrb_value self) MRB_API mrb_value mrb_time_at(mrb_state *mrb, time_t sec, time_t usec, enum mrb_timezone zone) { - return time_make_time(mrb, mrb_class_get_id(mrb, MRB_SYM(Time)), sec, usec * NSECS_PER_USEC, zone); + time_t nsec; + + /* Normalize microseconds to avoid overflow when converting to nanoseconds */ + if (usec >= USECS_PER_SEC || usec <= -USECS_PER_SEC) { + time_t sec_adjustment = usec / USECS_PER_SEC; + usec -= sec_adjustment * USECS_PER_SEC; + sec += sec_adjustment; + } + + nsec = usec * NSECS_PER_USEC; + return time_make_time(mrb, mrb_class_get_id(mrb, MRB_SYM(Time)), sec, nsec, zone); } /*