From 478ada3bf4fe81ec2e6bbf0fcd4e834c08da4a0b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 12 May 2026 11:18:57 +0900 Subject: [PATCH] fp_uscale.c: clamp precision in %g to avoid OOB in fixed_width When sprintf is called with a precision larger than the double's significand width (e.g. "%.51g"), fixed_width() indexed pow10 tables out of bounds and produced a negative shift exponent. Cap the internal digit count to 18 in the %g branch, matching the existing %e and %f branches; downstream loops already zero-pad to the caller's precision so visible output is unchanged. Co-authored-by: Claude --- mrbgems/mruby-sprintf/test/sprintf.rb | 10 ++++++++++ src/fp_uscale.c | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb index 80220137a..c513188a1 100644 --- a/mrbgems/mruby-sprintf/test/sprintf.rb +++ b/mrbgems/mruby-sprintf/test/sprintf.rb @@ -91,6 +91,16 @@ assert("String#% invalid format") do end end +assert("sprintf %g with high precision") do + # Regression test: precision values larger than double's significand + # used to cause out-of-bounds reads in fp_uscale's fixed_width(). + assert_equal "7", "%.*g" % [51, 7] + assert_equal "7.5", "%.*g" % [51, 7.5] + assert_equal "7", "%.51g" % 7.0 + assert_equal "7." + "0" * 50, "%#.51g" % 7.0 + assert_equal "7", "%.*g" % [1000, 7.0] +end + assert("sprintf with to_s mutating format string") do # The to_s callback must not be able to invalidate sprintf's internal # iteration pointers by mutating the format string. diff --git a/src/fp_uscale.c b/src/fp_uscale.c index 3136a178d..f8da4baca 100644 --- a/src/fp_uscale.c +++ b/src/fp_uscale.c @@ -1247,8 +1247,10 @@ mrb_format_float(mrb_float f, char *buf, size_t buf_size, char fmt, int prec, ch } else if (fmt == 'g') { /* g/G format */ - int fprec; - fixed_width((double)f, prec, &d, &p); + int fprec, n = prec; + if (n > 18) n = 18; + if (n < 1) n = 1; + fixed_width((double)f, n, &d, &p); nd = count_digits(d); exp = p + nd - 1;