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

ruby-changes:23061

From: shirosaki <ko1@a...>
Date: Thu, 22 Mar 2012 23:05:41 +0900 (JST)
Subject: [ruby-changes:23061] shirosaki:r35111 (trunk): * io.c (static int io_fflush): add the definition.

shirosaki	2012-03-22 23:05:31 +0900 (Thu, 22 Mar 2012)

  New Revision: 35111

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35111

  Log:
    * io.c (static int io_fflush): add the definition.
      Use it in set_binary_mode_with_seek_cur().
    
    * io.c (set_binary_mode_with_seek_cur): refactoring to split the
      content into io_unread(). Fix the possibility of buffer overflow.
    
    * io.c (io_unread): add new implementation for Windows. Previous one
      caused invalid cursor position using IO#pos with OS text mode. New
      one fixes the bug.
    
    * test/ruby/test_io_m17n.rb
      (TestIO_M17N#test_pos_dont_move_cursor_position): add a test for
      above bug.
      [ruby-core:43497] [Bug #6179]

  Modified files:
    trunk/ChangeLog
    trunk/io.c
    trunk/test/ruby/test_io_m17n.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 35110)
+++ ChangeLog	(revision 35111)
@@ -1,3 +1,20 @@
+Thu Mar 22 22:30:44 2012  Hiroshi Shirosaki  <h.shirosaki@g...>
+
+	* io.c (static int io_fflush): add the definition.
+	  Use it in set_binary_mode_with_seek_cur().
+
+	* io.c (set_binary_mode_with_seek_cur): refactoring to split the
+	  content into io_unread(). Fix the possibility of buffer overflow.
+
+	* io.c (io_unread): add new implementation for Windows. Previous one
+	  caused invalid cursor position using IO#pos with OS text mode. New
+	  one fixes the bug.
+
+	* test/ruby/test_io_m17n.rb
+	  (TestIO_M17N#test_pos_dont_move_cursor_position): add a test for
+	  above bug.
+	  [ruby-core:43497] [Bug #6179]
+
 Thu Mar 22 19:55:08 2012  Nobuyoshi Nakada  <nobu@r...>
 
 	* win32/win32.c (rb_w32_fstat, rb_w32_fstati64): convert FILETIME
Index: io.c
===================================================================
--- io.c	(revision 35110)
+++ io.c	(revision 35111)
@@ -377,6 +377,7 @@
 #define rb_sys_fail_path(path) rb_sys_fail_str(path)
 
 static int io_fflush(rb_io_t *);
+static rb_io_t *flush_before_seek(rb_io_t *fptr);
 
 #define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
 #define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
@@ -412,16 +413,12 @@
 	(ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
     }\
 } while(0)
+
 /*
- * We use io_seek to back cursor position when changing mode from text to binary,
- * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
- * conversion for working properly with mode change.
+ * IO unread with taking care of removed '\r' in text mode.
  */
-/*
- * Return previous translation mode.
- */
-static inline int
-set_binary_mode_with_seek_cur(rb_io_t *fptr)
+static void
+io_unread(rb_io_t *fptr)
 {
     off_t r, pos;
     ssize_t read_size;
@@ -429,23 +426,34 @@
     long newlines = 0;
     long extra_max;
     char *p;
+    char *buf;
 
-    if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
-
+    rb_io_check_closed(fptr);
     if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
-	return setmode(fptr->fd, O_BINARY);
+	return;
     }
 
-    if (io_fflush(fptr) < 0) {
-	rb_sys_fail(0);
+    errno = 0;
+    if (!rb_w32_fd_is_text(fptr->fd)) {
+	r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
+	if (r < 0 && errno) {
+	    if (errno == ESPIPE)
+		fptr->mode |= FMODE_DUPLEX;
+	    return;
+	}
+
+	fptr->rbuf.off = 0;
+	fptr->rbuf.len = 0;
+	return;
     }
-    errno = 0;
+
     pos = lseek(fptr->fd, 0, SEEK_CUR);
     if (pos < 0 && errno) {
 	if (errno == ESPIPE)
 	    fptr->mode |= FMODE_DUPLEX;
-	return setmode(fptr->fd, O_BINARY);
+	return;
     }
+
     /* add extra offset for removed '\r' in rbuf */
     extra_max = pos - fptr->rbuf.len;
     p = fptr->rbuf.ptr + fptr->rbuf.off;
@@ -454,6 +462,8 @@
 	if (extra_max == newlines) break;
 	p++;
     }
+
+    buf = ALLOC_N(char, fptr->rbuf.len + newlines);
     while (newlines >= 0) {
 	r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
 	if (newlines == 0) break;
@@ -461,7 +471,7 @@
 	    newlines--;
 	    continue;
 	}
-	read_size = _read(fptr->fd, fptr->rbuf.ptr, fptr->rbuf.len + newlines);
+	read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
 	if (read_size < 0) {
 	    rb_sys_fail_path(fptr->pathv);
 	}
@@ -475,6 +485,25 @@
     }
     fptr->rbuf.off = 0;
     fptr->rbuf.len = 0;
+    return;
+}
+
+/*
+ * We use io_seek to back cursor position when changing mode from text to binary,
+ * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
+ * conversion for working properly with mode change.
+ *
+ * Return previous translation mode.
+ */
+static inline int
+set_binary_mode_with_seek_cur(rb_io_t *fptr)
+{
+    if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
+
+    if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
+	return setmode(fptr->fd, O_BINARY);
+    }
+    flush_before_seek(fptr);
     return setmode(fptr->fd, O_BINARY);
 }
 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
@@ -605,6 +634,7 @@
     return rb_io_check_io(io);
 }
 
+#if !(defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32))
 static void
 io_unread(rb_io_t *fptr)
 {
@@ -624,6 +654,7 @@
     fptr->rbuf.len = 0;
     return;
 }
+#endif
 
 static rb_encoding *io_input_encoding(rb_io_t *fptr);
 
Index: test/ruby/test_io_m17n.rb
===================================================================
--- test/ruby/test_io_m17n.rb	(revision 35110)
+++ test/ruby/test_io_m17n.rb	(revision 35111)
@@ -2415,4 +2415,19 @@
     }
     assert_equal(paths.map(&:encoding), encs, bug6072)
   end
+
+  def test_pos_dont_move_cursor_position
+    bug6179 = '[ruby-core:43497]'
+    with_tmpdir {
+      str = "line one\r\nline two\r\nline three\r\n"
+      generate_file("tmp", str)
+      open("tmp", "r") do |f|
+        assert_equal("line one\n", f.readline)
+        assert_equal(10, f.pos, bug6179)
+        assert_equal("line two\n", f.readline, bug6179)
+        assert_equal(20, f.pos, bug6179)
+        assert_equal("line three\n", f.readline, bug6179)
+      end
+    }
+  end if /mswin|mingw/ =~ RUBY_PLATFORM
 end

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

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