From ae29ab7db9577fe45a5812eee0b364aaf976bab2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 19 May 2026 12:15:38 +0900 Subject: [PATCH] numeric.c: bounds-check float in Float#div before mrb_int cast `Float#div(Integer)` cast its receiver to mrb_int unconditionally, which is undefined behavior when the float is outside the representable mrb_int range. ASan reports the UB on inputs like `5e+56.div(1)`. Reported by ClusterFuzz testcase clusterfuzz-testcase-minimized-mruby_fuzzer-5137605569347584. Guard the cast with FIXABLE_FLOAT and route over-range receivers to mrb_bint_div when MRB_USE_BIGINT is defined (matching flo_rounding_int's pattern), or raise via mrb_int_overflow when not. Existing `(float in range).div(int)` semantics are unchanged. Co-authored-by: Claude --- src/numeric.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/numeric.c b/src/numeric.c index d3f370d7f..5d695c77e 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -351,6 +351,14 @@ flo_idiv(mrb_state *mrb, mrb_value xv) mrb_float x = mrb_float(xv); mrb_check_num_exact(mrb, x); mrb_int y = mrb_as_int(mrb, mrb_get_arg1(mrb)); + /* (mrb_int)x is UB when x is outside mrb_int range. */ + if (!FIXABLE_FLOAT(x)) { +#ifdef MRB_USE_BIGINT + return mrb_bint_div(mrb, mrb_bint_new_float(mrb, x), mrb_int_value(mrb, y)); +#else + mrb_int_overflow(mrb, "div"); +#endif + } return mrb_div_int_value(mrb, (mrb_int)x, y); }