diff options
author | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-04-14 18:02:01 +0000 |
---|---|---|
committer | naruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-04-14 18:02:01 +0000 |
commit | 0e84de2b9830e3b752ba5f8d97aa3c38924aafc5 (patch) | |
tree | cebda110a07b57b58f5e54c3ad3f6307eef46ad1 | |
parent | ffc3114c1a1762022b09af4f9b0417cfb54cd04b (diff) |
merge revision(s) 34785,35095,35098,35111,35152: [Backport #6294]
* io.c (set_binary_mode_with_seek_cur): reorder function qualifiers.
* test/ruby/test_io.rb (TestIO#test_pos_with_getc): added.
see [Bug #6179][ruby-core:43518]
* test/ruby/test_io.rb (TestIO#test_pos_with_getc): updated.
see [ruby-core:43550]
* 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]
* io.c (io_unread): fixed memory leak. report by nagachika via IRC.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@35328 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 31 | ||||
-rw-r--r-- | io.c | 65 | ||||
-rw-r--r-- | test/ruby/test_io.rb | 24 | ||||
-rw-r--r-- | test/ruby/test_io_m17n.rb | 15 | ||||
-rw-r--r-- | version.h | 6 |
5 files changed, 123 insertions, 18 deletions
@@ -1,3 +1,34 @@ +Sun Apr 15 03:00:54 2012 NAKAMURA Usaku <usa@ruby-lang.org> + + * io.c (io_unread): fixed memory leak. report by nagachika via IRC. + +Sun Apr 15 03:00:54 2012 Hiroshi Shirosaki <h.shirosaki@gmail.com> + + * 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] + +Sun Apr 15 03:00:54 2012 NAKAMURA Usaku <usa@ruby-lang.org> + + * test/ruby/test_io.rb (TestIO#test_pos_with_getc): updated. + see [ruby-core:43550] + +Sun Apr 15 03:00:54 2012 NAKAMURA Usaku <usa@ruby-lang.org> + + * test/ruby/test_io.rb (TestIO#test_pos_with_getc): added. + see [Bug #6179][ruby-core:43518] + Wed Apr 11 16:22:16 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> * ext/-test-/add_suffix/bug.c (ruby_add_suffix): no static @@ -222,6 +222,7 @@ rb_update_max_fd(int fd) #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) @@ -257,38 +258,47 @@ static int io_fflush(rb_io_t *); (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. - */ -/* - * Return previous translation mode. + * IO unread with taking care of removed '\r' in text mode. */ -inline static 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; long i; 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; + } + 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 = (long)(pos - fptr->rbuf.len); p = fptr->rbuf.ptr + fptr->rbuf.off; @@ -297,6 +307,8 @@ inline static int set_binary_mode_with_seek_cur(rb_io_t *fptr) { 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; @@ -304,8 +316,9 @@ inline static int set_binary_mode_with_seek_cur(rb_io_t *fptr) { 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) { + free(buf); rb_sys_fail_path(fptr->pathv); } if (read_size == fptr->rbuf.len) { @@ -316,8 +329,28 @@ inline static int set_binary_mode_with_seek_cur(rb_io_t *fptr) { newlines--; } } + free(buf); 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) @@ -448,6 +481,7 @@ rb_io_s_try_convert(VALUE dummy, VALUE io) return rb_io_check_io(io); } +#if !(defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)) static void io_unread(rb_io_t *fptr) { @@ -467,6 +501,7 @@ io_unread(rb_io_t *fptr) fptr->rbuf.len = 0; return; } +#endif static rb_encoding *io_input_encoding(rb_io_t *fptr); diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index bb6f239509..edf449dd5c 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -1307,6 +1307,30 @@ class TestIO < Test::Unit::TestCase end end + def test_pos_with_getc + bug6179 = '[ruby-core:43497]' + t = make_tempfile + ["", "t", "b"].each do |mode| + open(t.path, "w#{mode}") do |f| + f.write "0123456789\n" + end + + open(t.path, "r#{mode}") do |f| + assert_equal 0, f.pos, "mode=r#{mode}" + assert_equal '0', f.getc, "mode=r#{mode}" + assert_equal 1, f.pos, "mode=r#{mode}" + assert_equal '1', f.getc, "mode=r#{mode}" + assert_equal 2, f.pos, "mode=r#{mode}" + assert_equal '2', f.getc, "mode=r#{mode}" + assert_equal 3, f.pos, "mode=r#{mode}" + assert_equal '3', f.getc, "mode=r#{mode}" + assert_equal 4, f.pos, "mode=r#{mode}" + assert_equal '4', f.getc, "mode=r#{mode}" + end + end + end + + def test_sysseek t = make_tempfile diff --git a/test/ruby/test_io_m17n.rb b/test/ruby/test_io_m17n.rb index 2f71356f8e..c6cff18957 100644 --- a/test/ruby/test_io_m17n.rb +++ b/test/ruby/test_io_m17n.rb @@ -2347,4 +2347,19 @@ EOT } 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 @@ -1,10 +1,10 @@ #define RUBY_VERSION "1.9.3" -#define RUBY_PATCHLEVEL 179 +#define RUBY_PATCHLEVEL 180 -#define RUBY_RELEASE_DATE "2012-04-11" +#define RUBY_RELEASE_DATE "2012-04-15" #define RUBY_RELEASE_YEAR 2012 #define RUBY_RELEASE_MONTH 4 -#define RUBY_RELEASE_DAY 11 +#define RUBY_RELEASE_DAY 15 #include "ruby/version.h" |