[前][次][番号順一覧][スレッド一覧]

ruby-changes:54609

From: shyouhei <ko1@a...>
Date: Tue, 15 Jan 2019 15:42:08 +0900 (JST)
Subject: [ruby-changes:54609] shyouhei:r66824 (trunk): setbyte / ungetbyte allow out-of-range integers

shyouhei	2019-01-15 15:41:58 +0900 (Tue, 15 Jan 2019)

  New Revision: 66824

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=66824

  Log:
    setbyte / ungetbyte allow out-of-range integers
    
    * string.c: String#setbyte to accept arbitrary integers [Bug #15460]
    
    * io.c: ditto for IO#ungetbyte
    
    * ext/strringio/stringio.c: ditto for StringIO#ungetbyte

  Modified files:
    trunk/ext/stringio/stringio.c
    trunk/io.c
    trunk/spec/ruby/core/io/ungetbyte_spec.rb
    trunk/string.c
    trunk/test/ruby/test_m17n.rb
    trunk/test/stringio/test_stringio.rb
Index: string.c
===================================================================
--- string.c	(revision 66823)
+++ string.c	(revision 66824)
@@ -5409,7 +5409,6 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/string.c#L5409
 rb_str_setbyte(VALUE str, VALUE index, VALUE value)
 {
     long pos = NUM2LONG(index);
-    int byte = NUM2INT(value);
     long len = RSTRING_LEN(str);
     char *head, *left = 0;
     unsigned char *ptr;
@@ -5420,10 +5419,10 @@ rb_str_setbyte(VALUE str, VALUE index, V https://github.com/ruby/ruby/blob/trunk/string.c#L5419
         rb_raise(rb_eIndexError, "index %ld out of string", pos);
     if (pos < 0)
         pos += len;
-    if (byte < 0)
-        rb_raise(rb_eRangeError, "integer %d too small to convert into `unsigned char'", byte);
-    if (UCHAR_MAX < byte)
-        rb_raise(rb_eRangeError, "integer %d too big to convert into `unsigned char'", byte);
+
+    VALUE v = rb_to_int(value);
+    VALUE w = rb_int_modulo(v, INT2FIX(256));
+    unsigned char byte = NUM2INT(w) & 0xFF;
 
     if (!str_independent(str))
 	str_make_independent(str);
Index: test/stringio/test_stringio.rb
===================================================================
--- test/stringio/test_stringio.rb	(revision 66823)
+++ test/stringio/test_stringio.rb	(revision 66824)
@@ -453,9 +453,9 @@ class TestStringIO < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/test/stringio/test_stringio.rb#L453
     assert_equal(0, t.pos)
     assert_equal("\u{30eb 30d3 30fc}\u7d05\u7389bar\n", s)
 
-    assert_raise(RangeError) {t.ungetbyte(-1)}
-    assert_raise(RangeError) {t.ungetbyte(256)}
-    assert_raise(RangeError) {t.ungetbyte(1<<64)}
+    assert_nothing_raised {t.ungetbyte(-1)}
+    assert_nothing_raised {t.ungetbyte(256)}
+    assert_nothing_raised {t.ungetbyte(1<<64)}
   end
 
   def test_ungetc
Index: test/ruby/test_m17n.rb
===================================================================
--- test/ruby/test_m17n.rb	(revision 66823)
+++ test/ruby/test_m17n.rb	(revision 66824)
@@ -1526,13 +1526,13 @@ class TestM17N < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_m17n.rb#L1526
 
   def test_setbyte_range
     s = u("\xE3\x81\x82\xE3\x81\x84")
-    assert_raise(RangeError) { s.setbyte(0, -1) }
-    assert_nothing_raised    { s.setbyte(0, 0x00) }
-    assert_nothing_raised    { s.setbyte(0, 0x7F) }
-    assert_nothing_raised    { s.setbyte(0, 0x80) }
-    assert_nothing_raised    { s.setbyte(0, 0xff) }
-    assert_raise(RangeError) { s.setbyte(0, 0x100) }
-    assert_raise(RangeError) { s.setbyte(0, 0x4f7574206f6620636861722072616e6765) }
+    assert_nothing_raised { s.setbyte(0, -1) }
+    assert_nothing_raised { s.setbyte(0, 0x00) }
+    assert_nothing_raised { s.setbyte(0, 0x7F) }
+    assert_nothing_raised { s.setbyte(0, 0x80) }
+    assert_nothing_raised { s.setbyte(0, 0xff) }
+    assert_nothing_raised { s.setbyte(0, 0x100) }
+    assert_nothing_raised { s.setbyte(0, 0x4f7574206f6620636861722072616e6765) }
   end
 
   def test_compatible
Index: ext/stringio/stringio.c
===================================================================
--- ext/stringio/stringio.c	(revision 66823)
+++ ext/stringio/stringio.c	(revision 66824)
@@ -805,33 +805,26 @@ strio_ungetbyte(VALUE self, VALUE c) https://github.com/ruby/ruby/blob/trunk/ext/stringio/stringio.c#L805
     struct StringIO *ptr = readable(self);
 
     check_modifiable(ptr);
-    if (NIL_P(c)) return Qnil;
-    if (FIXNUM_P(c)) {
-        int i = FIX2INT(c);
-        if (0 <= i && i <= UCHAR_MAX) {
-            char buf[1];
-            buf[0] = (char)i;
-            return strio_unget_bytes(ptr, buf, 1);
-        }
-        else {
-            rb_raise(rb_eRangeError,
-                "integer %d too big to convert into `unsigned char'", i);
-        }
-    }
-    else if (RB_TYPE_P(c, T_BIGNUM)) {
-        rb_raise(rb_eRangeError, "bignum too big to convert into `unsigned char'");
-    }
-    else {
-        char *cp;
-        long cl;
-	SafeStringValue(c);
-	cp = RSTRING_PTR(c);
-	cl = RSTRING_LEN(c);
-	if (cl == 0) return Qnil;
-	strio_unget_bytes(ptr, cp, cl);
-	RB_GC_GUARD(c);
-	return Qnil;
+    switch (TYPE(c)) {
+      case T_NIL:
+        return Qnil;
+      case T_FIXNUM:
+      case T_BIGNUM: ;
+        /* rb_int_modulo() not visible from exts */
+        VALUE v = rb_funcall(c, rb_intern("modulo"), 1, INT2FIX(256));
+        unsigned char cc = NUM2INT(v) & 0xFF;
+        c = rb_str_new((const char *)&cc, 1);
+        break;
+      default:
+        SafeStringValue(c);
     }
+
+    const char *cp = RSTRING_PTR(c);
+    long cl = RSTRING_LEN(c);
+    if (cl == 0) return Qnil;
+    strio_unget_bytes(ptr, cp, cl);
+    RB_GC_GUARD(c);
+    return Qnil;
 }
 
 static VALUE
Index: io.c
===================================================================
--- io.c	(revision 66823)
+++ io.c	(revision 66824)
@@ -4258,23 +4258,17 @@ rb_io_ungetbyte(VALUE io, VALUE b) https://github.com/ruby/ruby/blob/trunk/io.c#L4258
 
     GetOpenFile(io, fptr);
     rb_io_check_byte_readable(fptr);
-    if (NIL_P(b)) return Qnil;
-    if (FIXNUM_P(b)) {
-        int i = FIX2INT(b);
-        if (0 <= i && i <= UCHAR_MAX) {
-            unsigned char cc = i & 0xFF;
-            b = rb_str_new((const char *)&cc, 1);
-        }
-        else {
-            rb_raise(rb_eRangeError,
-                "integer %d too big to convert into `unsigned char'", i);
-        }
-    }
-    else if (RB_TYPE_P(b, T_BIGNUM)) {
-        rb_raise(rb_eRangeError, "bignum too big to convert into `unsigned char'");
-    }
-    else {
-	SafeStringValue(b);
+    switch (TYPE(b)) {
+      case T_NIL:
+        return Qnil;
+      case T_FIXNUM:
+      case T_BIGNUM: ;
+        VALUE v = rb_int_modulo(b, INT2FIX(256));
+        unsigned char c = NUM2INT(v) & 0xFF;
+        b = rb_str_new((const char *)&c, 1);
+        break;
+      default:
+        SafeStringValue(b);
     }
     io_ungetbyte(b, fptr);
     return Qnil;
Index: spec/ruby/core/io/ungetbyte_spec.rb
===================================================================
--- spec/ruby/core/io/ungetbyte_spec.rb	(revision 66823)
+++ spec/ruby/core/io/ungetbyte_spec.rb	(revision 66824)
@@ -49,13 +49,21 @@ describe "IO#ungetbyte" do https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/io/ungetbyte_spec.rb#L49
     end
   end
 
-  ruby_version_is '2.6' do
+  ruby_version_is '2.6'...'2.7' do
     it "is an RangeError if the integer is not in 8bit" do
       for i in [4095, 0x4f7574206f6620636861722072616e6765] do
         lambda { @io.ungetbyte(i) }.should raise_error(RangeError)
       end
     end
   end
+
+  ruby_version_is '2.7' do
+    it "never raises RangeError" do
+      for i in [4095, 0x4f7574206f6620636861722072616e6765] do
+        lambda { @io.ungetbyte(i) }.should_not raise_error
+      end
+    end
+  end
 
   it "raises an IOError if the IO is closed" do
     @io.close

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]