summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-14 18:02:01 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-14 18:02:01 +0000
commit0e84de2b9830e3b752ba5f8d97aa3c38924aafc5 (patch)
treecebda110a07b57b58f5e54c3ad3f6307eef46ad1
parentffc3114c1a1762022b09af4f9b0417cfb54cd04b (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--ChangeLog31
-rw-r--r--io.c65
-rw-r--r--test/ruby/test_io.rb24
-rw-r--r--test/ruby/test_io_m17n.rb15
-rw-r--r--version.h6
5 files changed, 123 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index 4ec2e0d949..ee15273a52 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/io.c b/io.c
index d491267733..4bb53cb969 100644
--- a/io.c
+++ b/io.c
@@ -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
diff --git a/version.h b/version.h
index fa32cc053f..a270fcea70 100644
--- a/version.h
+++ b/version.h
@@ -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"