rb_io_puts should not write zero length strings. (#7806)

This commit is contained in:
Samuel Williams 2023-05-15 11:13:51 +09:00 committed by GitHub
parent 91c004885f
commit 0b2613f443
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2023-05-15 02:14:20 +00:00
Merged-By: ioquatix <samuel@codeotaku.com>
2 changed files with 52 additions and 16 deletions

34
io.c
View File

@ -1327,16 +1327,17 @@ rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
static ssize_t static ssize_t
rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt) rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
{ {
if (!iovcnt) return 0;
VALUE scheduler = rb_fiber_scheduler_current(); VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) { if (scheduler != Qnil) {
for (int i = 0; i < iovcnt; i += 1) { // This path assumes at least one `iov`:
VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[i].iov_base, iov[i].iov_len, 0); VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
if (!UNDEF_P(result)) { if (!UNDEF_P(result)) {
return rb_fiber_scheduler_io_result_apply(result); return rb_fiber_scheduler_io_result_apply(result);
} }
} }
}
struct io_internal_writev_struct iis = { struct io_internal_writev_struct iis = {
.th = rb_thread_current(), .th = rb_thread_current(),
@ -2041,7 +2042,7 @@ io_binwritev_internal(VALUE arg)
while (remaining) { while (remaining) {
long result = rb_writev_internal(fptr, iov, iovcnt); long result = rb_writev_internal(fptr, iov, iovcnt);
if (result > 0) { if (result >= 0) {
offset += result; offset += result;
if (fptr->wbuf.ptr && fptr->wbuf.len) { if (fptr->wbuf.ptr && fptr->wbuf.len) {
if (offset < (size_t)fptr->wbuf.len) { if (offset < (size_t)fptr->wbuf.len) {
@ -8914,7 +8915,6 @@ io_puts_ary(VALUE ary, VALUE out, int recur)
VALUE VALUE
rb_io_puts(int argc, const VALUE *argv, VALUE out) rb_io_puts(int argc, const VALUE *argv, VALUE out)
{ {
int i, n;
VALUE line, args[2]; VALUE line, args[2];
/* if no argument given, print newline. */ /* if no argument given, print newline. */
@ -8922,22 +8922,30 @@ rb_io_puts(int argc, const VALUE *argv, VALUE out)
rb_io_write(out, rb_default_rs); rb_io_write(out, rb_default_rs);
return Qnil; return Qnil;
} }
for (i=0; i<argc; i++) { for (int i = 0; i < argc; i++) {
// Convert the argument to a string:
if (RB_TYPE_P(argv[i], T_STRING)) { if (RB_TYPE_P(argv[i], T_STRING)) {
line = argv[i]; line = argv[i];
goto string;
} }
if (rb_exec_recursive(io_puts_ary, argv[i], out)) { else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
continue; continue;
} }
else {
line = rb_obj_as_string(argv[i]); line = rb_obj_as_string(argv[i]);
string: }
n = 0;
args[n++] = line; // Write the line:
if (RSTRING_LEN(line) == 0 || int n = 0;
!rb_str_end_with_asciichar(line, '\n')) { if (RSTRING_LEN(line) == 0) {
args[n++] = rb_default_rs; args[n++] = rb_default_rs;
} }
else {
args[n++] = line;
if (!rb_str_end_with_asciichar(line, '\n')) {
args[n++] = rb_default_rs;
}
}
rb_io_writev(out, n, args); rb_io_writev(out, n, args);
} }

View File

@ -170,6 +170,34 @@ class TestFiberIO < Test::Unit::TestCase
assert_predicate(o, :closed?) assert_predicate(o, :closed?)
end end
def test_puts_empty
omit "UNIXSocket is not defined!" unless defined?(UNIXSocket)
i, o = UNIXSocket.pair
i.nonblock = false
o.nonblock = false
thread = Thread.new do
# This scheduler provides non-blocking `io_read`/`io_write`:
scheduler = IOBufferScheduler.new
Fiber.set_scheduler scheduler
Fiber.schedule do
# This was causing a segfault on older Ruby.
o.puts ""
o.puts nil
o.close
end
end
thread.join
message = i.read
i.close
assert_equal $/*2, message
end
def test_io_select def test_io_select
omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) omit "UNIXSocket is not defined!" unless defined?(UNIXSocket)