diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index c15099ff..c64c6e24 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -2846,6 +2846,8 @@ rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception) static inline VALUE rb_str_convert_to_BigDecimal(VALUE val, int raise_exception) { + StringValue(val); + rb_must_asciicompat(val); if (!raise_exception && memchr(RSTRING_PTR(val), '\0', RSTRING_LEN(val))) return Qnil; const char *c_str = StringValueCStr(val); VALUE bd = rb_cstr_convert_to_BigDecimal(c_str, raise_exception); @@ -3012,6 +3014,12 @@ f_BigDecimal(int argc, VALUE *argv, VALUE self) static VALUE BigDecimal_s_interpret_loosely(VALUE klass, VALUE str) { + StringValue(str); + rb_must_asciicompat(str); + /* Like String#to_f, ignore everything after an embedded NUL */ + const char *p = RSTRING_PTR(str); + const char *nul = memchr(p, '\0', RSTRING_LEN(str)); + if (nul) str = rb_str_subseq(str, 0, nul - p); char const *c_str = StringValueCStr(str); NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true); RB_GC_GUARD(str); diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb index 5bfd98cf..a24bdbcc 100644 --- a/test/bigdecimal/test_bigdecimal.rb +++ b/test/bigdecimal/test_bigdecimal.rb @@ -113,6 +113,12 @@ def test_BigDecimal_issue_192 assert_equal(BigDecimal(int), big, "[ruby/bigdecimal#192]") end + def test_BigDecimal_with_ascii_incompatible_string + str = "123".encode("UTF-16LE") + assert_raise(Encoding::CompatibilityError) { BigDecimal(str) } + assert_raise(Encoding::CompatibilityError) { BigDecimal(str, exception: false) } + end + def test_BigDecimal_with_invalid_string [ '', '.', 'e1', 'd1', '.e', '.d', '1.e', '1.d', '.1e', '.1d', diff --git a/test/bigdecimal/test_bigdecimal_util.rb b/test/bigdecimal/test_bigdecimal_util.rb index e2ead321..67693935 100644 --- a/test/bigdecimal/test_bigdecimal_util.rb +++ b/test/bigdecimal/test_bigdecimal_util.rb @@ -125,6 +125,9 @@ def test_String_to_d assert_equal(BigDecimal('1.2'), "1.2.3".to_d) assert_equal(BigDecimal('1'), "1.".to_d) assert_equal(BigDecimal('1'), "1e".to_d) + assert_equal(BigDecimal('1'), "1\0 2".to_d) + assert_equal(BigDecimal('0'), "\0 1".to_d) + assert_raise(Encoding::CompatibilityError) { "1".encode("UTF-16LE").to_d } assert("2.5".to_d.frozen?) end