summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'io.c')
-rw-r--r--io.c75
1 files changed, 61 insertions, 14 deletions
diff --git a/io.c b/io.c
index 57164d1042..7c8f2c9762 100644
--- a/io.c
+++ b/io.c
@@ -1816,15 +1816,31 @@ io_bufread(char *ptr, long len, rb_io_t *fptr)
return len - n;
}
+struct bufread_arg {
+ char *str_ptr;
+ long len;
+ rb_io_t *fptr;
+};
+
+static VALUE
+bufread_call(VALUE arg)
+{
+ struct bufread_arg *p = (struct bufread_arg *)arg;
+ p->len = io_bufread(p->str_ptr, p->len, p->fptr);
+ return Qundef;
+}
+
static long
io_fread(VALUE str, long offset, rb_io_t *fptr)
{
long len;
+ struct bufread_arg arg;
- rb_str_locktmp(str);
- len = io_bufread(RSTRING_PTR(str) + offset, RSTRING_LEN(str) - offset,
- fptr);
- rb_str_unlocktmp(str);
+ arg.str_ptr = RSTRING_PTR(str) + offset;
+ arg.len = RSTRING_LEN(str) - offset;
+ arg.fptr = fptr;
+ rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
+ len = arg.len;
if (len < 0) rb_sys_fail_path(fptr->pathv);
return len;
}
@@ -2124,12 +2140,27 @@ rb_io_set_nonblock(rb_io_t *fptr)
}
}
+struct read_internal_arg {
+ int fd;
+ char *str_ptr;
+ long len;
+};
+
+static VALUE
+read_internal_call(VALUE arg)
+{
+ struct read_internal_arg *p = (struct read_internal_arg *)arg;
+ p->len = rb_read_internal(p->fd, p->str_ptr, p->len);
+ return Qundef;
+}
+
static VALUE
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
{
rb_io_t *fptr;
VALUE length, str;
long n, len;
+ struct read_internal_arg arg;
rb_scan_args(argc, argv, "11", &length, &str);
@@ -2154,9 +2185,11 @@ io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
if (nonblock) {
rb_io_set_nonblock(fptr);
}
- rb_str_locktmp(str);
- n = rb_read_internal(fptr->fd, RSTRING_PTR(str), len);
- rb_str_unlocktmp(str);
+ arg.fd = fptr->fd;
+ arg.str_ptr = RSTRING_PTR(str);
+ arg.len = len;
+ rb_str_locktmp_ensure(str, read_internal_call, (VALUE)&arg);
+ n = arg.len;
if (n < 0) {
if (!nonblock && rb_io_wait_readable(fptr->fd))
goto again;
@@ -3151,7 +3184,11 @@ io_getc(rb_io_t *fptr, rb_encoding *enc)
}
else {
io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
- cr = ISASCII(r) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
+ cr = ENC_CODERANGE_VALID;
+ if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
+ ISASCII(RSTRING_PTR(str)[0])) {
+ cr = ENC_CODERANGE_7BIT;
+ }
}
str = io_enc_str(str, fptr);
ENC_CODERANGE_SET(str, cr);
@@ -4027,11 +4064,16 @@ rb_io_close_read(VALUE io)
write_io = GetWriteIO(io);
if (io != write_io) {
rb_io_t *wfptr;
- rb_io_fptr_cleanup(fptr, FALSE);
GetOpenFile(write_io, wfptr);
+ wfptr->pid = fptr->pid;
+ fptr->pid = 0;
RFILE(io)->fptr = wfptr;
- RFILE(write_io)->fptr = NULL;
- rb_io_fptr_finalize(fptr);
+ /* bind to write_io temporarily to get rid of memory/fd leak */
+ fptr->tied_io_for_writing = 0;
+ fptr->mode &= ~FMODE_DUPLEX;
+ RFILE(write_io)->fptr = fptr;
+ rb_io_fptr_cleanup(fptr, FALSE);
+ /* should not finalize fptr because another thread may be reading it */
return Qnil;
}
@@ -4087,12 +4129,12 @@ rb_io_close_write(VALUE io)
rb_raise(rb_eIOError, "closing non-duplex IO for writing");
}
- rb_io_close(write_io);
if (io != write_io) {
GetOpenFile(io, fptr);
fptr->tied_io_for_writing = 0;
fptr->mode &= ~FMODE_DUPLEX;
}
+ rb_io_close(write_io);
return Qnil;
}
@@ -4171,6 +4213,7 @@ rb_io_syswrite(VALUE io, VALUE str)
}
n = rb_write_internal(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
+ RB_GC_GUARD(str);
if (n == -1) rb_sys_fail_path(fptr->pathv);
@@ -4199,6 +4242,7 @@ rb_io_sysread(int argc, VALUE *argv, VALUE io)
VALUE len, str;
rb_io_t *fptr;
long n, ilen;
+ struct read_internal_arg arg;
rb_scan_args(argc, argv, "11", &len, &str);
ilen = NUM2LONG(len);
@@ -4218,8 +4262,11 @@ rb_io_sysread(int argc, VALUE *argv, VALUE io)
rb_io_check_closed(fptr);
rb_str_locktmp(str);
- n = rb_read_internal(fptr->fd, RSTRING_PTR(str), ilen);
- rb_str_unlocktmp(str);
+ arg.fd = fptr->fd;
+ arg.str_ptr = RSTRING_PTR(str);
+ arg.len = ilen;
+ rb_ensure(read_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
+ n = arg.len;
if (n == -1) {
rb_sys_fail_path(fptr->pathv);