diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | numeric.c | 30 | ||||
-rw-r--r-- | string.c | 15 |
3 files changed, 47 insertions, 5 deletions
@@ -1,3 +1,10 @@ +Wed Oct 13 12:53:43 2010 NARUSE, Yui <naruse@ruby-lang.org> + + * numeric.c (rb_num_to_uint): added to check the range of arguments. + Mainly for negative value with NUM2UINT on 32bit environment. + + * string.c (rb_str_concat): use rb_num_to_uint. + Wed Oct 13 12:10:02 2010 NAKAMURA Usaku <usa@ruby-lang.org> * thread_win32.c (w32_error): get English message first, instead @@ -113,6 +113,36 @@ rb_num_zerodiv(void) rb_raise(rb_eZeroDivError, "divided by 0"); } +/* experimental API */ +int +rb_num_to_uint(VALUE val, unsigned int *ret) +{ +#define NUMERR_TYPE 1 +#define NUMERR_NEGATIVE 2 +#define NUMERR_TOOLARGE 3 + if (FIXNUM_P(val)) { + long v = FIX2LONG(val); + if (v > UINT_MAX) return NUMERR_TOOLARGE; + if (v < 0) return NUMERR_NEGATIVE; + *ret = (unsigned int)v; + return 0; + } + + switch (TYPE(val)) { + case T_BIGNUM: + if (RBIGNUM_NEGATIVE_P(val)) return NUMERR_NEGATIVE; +#if SIZEOF_INT < SIZEOF_LONG + /* long is 64bit */ + return NUMERR_TOOLARGE; +#else + /* long is 32bit */ + if (RBIGNUM_LEN(x) > DIGSPERLONG) return NUMERR_TOOLARGE; + *ret = (unsigned int)rb_big2ulong((VALUE)val); + return 0; +#endif + } + return NUMERR_TYPE; +} /* * call-seq: @@ -2001,6 +2001,7 @@ rb_str_append(VALUE str, VALUE str2) return rb_str_buf_append(str, str2); } +int rb_num_to_uint(VALUE val, unsigned int *ret); /* * call-seq: @@ -2023,11 +2024,15 @@ rb_str_concat(VALUE str1, VALUE str2) { unsigned int lc; - if (FIXNUM_P(str2)) { - lc = FIX2UINT(str2); - } - else if (TYPE(str2) == T_BIGNUM) { - lc = NUM2UINT(str2); + if (FIXNUM_P(str2) || TYPE(str2) == T_BIGNUM) { + if (rb_num_to_uint(str2, &lc) == 0) { + } + else if (FIXNUM_P(str2)) { + rb_raise(rb_eRangeError, "%ld out of char range", FIX2LONG(str2)); + } + else { + rb_raise(rb_eRangeError, "bignum out of char range"); + } } else { return rb_str_append(str1, str2); |