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 <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-05-19 12:15:38 +09:00
parent 73255d3b70
commit ae29ab7db9
+8
View File
@@ -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);
}