aboutsummaryrefslogtreecommitdiffstats
path: root/io.c
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-12-21 00:26:24 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-12-21 00:26:24 +0000
commite74ec4ebd0de14c808dc0ffbaf05b48c6da1367d (patch)
tree8a909a744d983ccbfc70ad514594654b95d2a9e2 /io.c
parent566efc55bcfd9f3d4d3ab22e4217d688a08244bf (diff)
downloadruby-e74ec4ebd0de14c808dc0ffbaf05b48c6da1367d.tar.gz
io.c: IO#pwrite uses tmp buffer to avoid parallel modification
Since we release GVL, we must freeze and duplicate the string buffer to prevent other threads from modifying our buffer while we are waiting on pwrite(2). * io.c (rb_io_pwrite): use_rb_str_tmp_frozen_{acquire/release} [Bug #14195] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61376 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'io.c')
-rw-r--r--io.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/io.c b/io.c
index 24f721e8fd..f2d1f84be8 100644
--- a/io.c
+++ b/io.c
@@ -5186,12 +5186,11 @@ rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
rb_io_t *fptr;
ssize_t n;
struct prdwr_internal_arg arg;
+ VALUE tmp;
if (!RB_TYPE_P(str, T_STRING))
str = rb_obj_as_string(str);
- arg.buf = RSTRING_PTR(str);
- arg.count = (size_t)RSTRING_LEN(str);
arg.offset = NUM2OFFT(offset);
io = GetWriteIO(io);
@@ -5199,10 +5198,13 @@ rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
rb_io_check_writable(fptr);
arg.fd = fptr->fd;
- n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
- RB_GC_GUARD(str);
+ tmp = rb_str_tmp_frozen_acquire(str);
+ arg.buf = RSTRING_PTR(tmp);
+ arg.count = (size_t)RSTRING_LEN(tmp);
+ n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
if (n == -1) rb_sys_fail_path(fptr->pathv);
+ rb_str_tmp_frozen_release(str, tmp);
return SSIZET2NUM(n);
}