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

ruby-changes:45399

From: normal <ko1@a...>
Date: Tue, 31 Jan 2017 07:13:23 +0900 (JST)
Subject: [ruby-changes:45399] normal:r57472 (trunk): io.c (rb_io_syswrite): avoid leaving garbage after write

normal	2017-01-31 07:03:57 +0900 (Tue, 31 Jan 2017)

  New Revision: 57472

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

  Log:
    io.c (rb_io_syswrite): avoid leaving garbage after write
    
    As with IO#write, IO#syswrite also generates garbage which can
    be harmful in hand-coded read-write loops.
    
    * io.c (swrite_arg, swrite_do, swrite_end): new
      (rb_io_syswrite): use new functions to cleanup garbage
      [ruby-core:78898] [Bug #13085]

  Modified files:
    trunk/io.c
    trunk/test/ruby/test_io.rb
Index: test/ruby/test_io.rb
===================================================================
--- test/ruby/test_io.rb	(revision 57471)
+++ test/ruby/test_io.rb	(revision 57472)
@@ -3512,11 +3512,13 @@ __END__ https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L3512
         with_pipe do |r, w|
           before = ObjectSpace.count_objects(res)[:T_STRING]
           n = w.write(buf)
+          s = w.syswrite(buf)
           after = ObjectSpace.count_objects(res)[:T_STRING]
           assert_equal before, after,
             'no strings left over after write [ruby-core:78898] [Bug #13085]'
           assert_not_predicate buf, :frozen?, 'no inadvertant freeze'
-          assert_equal buf.bytesize, n, 'wrote expected size'
+          assert_equal buf.bytesize, n, 'write wrote expected size'
+          assert_equal s, n, 'syswrite wrote expected size'
         end
       end
     end
Index: io.c
===================================================================
--- io.c	(revision 57471)
+++ io.c	(revision 57472)
@@ -4745,6 +4745,34 @@ rb_io_sysseek(int argc, VALUE *argv, VAL https://github.com/ruby/ruby/blob/trunk/io.c#L4745
     return OFFT2NUM(pos);
 }
 
+struct swrite_arg {
+    VALUE orig;
+    VALUE tmp;
+    rb_io_t *fptr;
+};
+
+static VALUE
+swrite_do(VALUE arg)
+{
+    struct swrite_arg *sa = (struct swrite_arg *)arg;
+    const char *ptr;
+    long len;
+
+    RSTRING_GETMEM(sa->tmp, ptr, len);
+
+    return (VALUE)rb_write_internal(sa->fptr->fd, ptr, len);
+}
+
+static VALUE
+swrite_end(VALUE arg)
+{
+    struct swrite_arg *sa = (struct swrite_arg *)arg;
+
+    rb_str_tmp_frozen_release(sa->orig, sa->tmp);
+
+    return Qfalse;
+}
+
 /*
  *  call-seq:
  *     ios.syswrite(string)   -> integer
@@ -4761,26 +4789,25 @@ rb_io_sysseek(int argc, VALUE *argv, VAL https://github.com/ruby/ruby/blob/trunk/io.c#L4789
 static VALUE
 rb_io_syswrite(VALUE io, VALUE str)
 {
-    rb_io_t *fptr;
+    struct swrite_arg sa;
     long n;
 
     if (!RB_TYPE_P(str, T_STRING))
 	str = rb_obj_as_string(str);
 
     io = GetWriteIO(io);
-    GetOpenFile(io, fptr);
-    rb_io_check_writable(fptr);
-
-    str = rb_str_new_frozen(str);
+    GetOpenFile(io, sa.fptr);
+    rb_io_check_writable(sa.fptr);
 
-    if (fptr->wbuf.len) {
+    if (sa.fptr->wbuf.len) {
 	rb_warn("syswrite for buffered IO");
     }
 
-    n = rb_write_internal(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
-    RB_GC_GUARD(str);
+    sa.orig = str;
+    sa.tmp = rb_str_tmp_frozen_acquire(str);
+    n = (long)rb_ensure(swrite_do, (VALUE)&sa, swrite_end, (VALUE)&sa);
 
-    if (n == -1) rb_sys_fail_path(fptr->pathv);
+    if (n == -1) rb_sys_fail_path(sa.fptr->pathv);
 
     return LONG2FIX(n);
 }

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

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