From 067d9e9ce97dd42b8b13eef10031b0fa9cf23a1f Mon Sep 17 00:00:00 2001 From: nobu Date: Sat, 9 Sep 2017 09:16:59 +0000 Subject: [PATCH] sprintf.c: NULL as str * sprintf.c (ruby_vsnprintf, ruby_snprintf): allow NULL as str, just count the expected buffer size. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59789 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/-test-/printf/printf.c | 8 ++++++++ sprintf.c | 20 ++++++++++++++------ test/-ext-/test_printf.rb | 4 ++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/ext/-test-/printf/printf.c b/ext/-test-/printf/printf.c index 666f5592e5..e793bb7a48 100644 --- a/ext/-test-/printf/printf.c +++ b/ext/-test-/printf/printf.c @@ -90,6 +90,13 @@ printf_test_call(int argc, VALUE *argv, VALUE self) return rb_assoc_new(result, rb_usascii_str_new_cstr(format)); } +static VALUE +snprintf_count(VALUE self, VALUE str) +{ + int n = ruby_snprintf(NULL, 0, "%s", StringValueCStr(str)); + return INT2FIX(n); +} + void Init_printf(void) { @@ -98,4 +105,5 @@ Init_printf(void) rb_define_singleton_method(m, "v", printf_test_v, 1); rb_define_singleton_method(m, "q", printf_test_q, 1); rb_define_singleton_method(m, "call", printf_test_call, -1); + rb_define_singleton_method(m, "sncount", snprintf_count, 1); } diff --git a/sprintf.c b/sprintf.c index 4ee7e1d4f0..2bd4966a1b 100644 --- a/sprintf.c +++ b/sprintf.c @@ -1261,21 +1261,29 @@ ruby_ultoa(unsigned long val, char *endp, int base, int flags) return BSD__ultoa(val, endp, base, octzero, xdigs); } +static int ruby_do_vsnprintf(char *str, size_t n, const char *fmt, va_list ap); + int ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap) +{ + if (str && (ssize_t)n < 1) + return (EOF); + return ruby_do_vsnprintf(str, n, fmt, ap); +} + +static int +ruby_do_vsnprintf(char *str, size_t n, const char *fmt, va_list ap) { int ret; rb_printf_buffer f; - if ((int)n < 1) - return (EOF); f._flags = __SWR | __SSTR; f._bf._base = f._p = (unsigned char *)str; - f._bf._size = f._w = n - 1; + f._bf._size = f._w = str ? (n - 1) : 0; f.vwrite = BSD__sfvwrite; f.vextra = 0; ret = (int)BSD_vfprintf(&f, fmt, ap); - *f._p = 0; + if (str) *f._p = 0; return ret; } @@ -1285,11 +1293,11 @@ ruby_snprintf(char *str, size_t n, char const *fmt, ...) int ret; va_list ap; - if ((int)n < 1) + if (str && (ssize_t)n < 1) return (EOF); va_start(ap, fmt); - ret = ruby_vsnprintf(str, n, fmt, ap); + ret = ruby_do_vsnprintf(str, n, fmt, ap); va_end(ap); return ret; } diff --git a/test/-ext-/test_printf.rb b/test/-ext-/test_printf.rb index 4e4f5b4695..cd3ba76364 100644 --- a/test/-ext-/test_printf.rb +++ b/test/-ext-/test_printf.rb @@ -184,4 +184,8 @@ class Test_SPrintf < Test::Unit::TestCase assert_equal(" a", Bug::Printf.("s", "a", width: 3, prec: 3)[0]) assert_equal("a ", Bug::Printf.("s", "a", minus: true, width: 3, prec: 3)[0]) end + + def test_snprintf_count + assert_equal(3, Bug::Printf.sncount("foo")) + end end