Skip to content

Commit

Permalink
rb_io_puts should not write zero length strings. (#7806)
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed May 15, 2023
1 parent 91c0048 commit 0b2613f
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 16 deletions.
40 changes: 24 additions & 16 deletions io.c
Expand Up @@ -1327,14 +1327,15 @@ rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
static ssize_t
rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
{
if (!iovcnt) return 0;

VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
for (int i = 0; i < iovcnt; i += 1) {
VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[i].iov_base, iov[i].iov_len, 0);
// This path assumes at least one `iov`:
VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);

if (!UNDEF_P(result)) {
return rb_fiber_scheduler_io_result_apply(result);
}
if (!UNDEF_P(result)) {
return rb_fiber_scheduler_io_result_apply(result);
}
}

Expand Down Expand Up @@ -2041,7 +2042,7 @@ io_binwritev_internal(VALUE arg)
while (remaining) {
long result = rb_writev_internal(fptr, iov, iovcnt);

if (result > 0) {
if (result >= 0) {
offset += result;
if (fptr->wbuf.ptr && fptr->wbuf.len) {
if (offset < (size_t)fptr->wbuf.len) {
Expand Down Expand Up @@ -8914,30 +8915,37 @@ io_puts_ary(VALUE ary, VALUE out, int recur)
VALUE
rb_io_puts(int argc, const VALUE *argv, VALUE out)
{
int i, n;
VALUE line, args[2];

/* if no argument given, print newline. */
if (argc == 0) {
rb_io_write(out, rb_default_rs);
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)) {
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;
}
line = rb_obj_as_string(argv[i]);
string:
n = 0;
args[n++] = line;
if (RSTRING_LEN(line) == 0 ||
!rb_str_end_with_asciichar(line, '\n')) {
else {
line = rb_obj_as_string(argv[i]);
}

// Write the line:
int n = 0;
if (RSTRING_LEN(line) == 0) {
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);
}

Expand Down
28 changes: 28 additions & 0 deletions test/fiber/test_io.rb
Expand Up @@ -170,6 +170,34 @@ def test_read_write_blocking
assert_predicate(o, :closed?)
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
omit "UNIXSocket is not defined!" unless defined?(UNIXSocket)

Expand Down

0 comments on commit 0b2613f

Please sign in to comment.