diff options
| author | nagachika <nagachika@ruby-lang.org> | 2023-07-22 13:03:22 +0900 |
|---|---|---|
| committer | nagachika <nagachika@ruby-lang.org> | 2023-07-22 13:03:22 +0900 |
| commit | ea89527a76a84741463c304246db2dd3a5df845b (patch) | |
| tree | e211be19a5741aef1a466a23037de21df9487d06 | |
| parent | 465eb7418d7ed91f5f0c75da77765c7f5ef8354f (diff) | |
merge revision(s) 0b2613f44309bddae45562c9f3a14ed43e56959b: [Backport #19640]
`rb_io_puts` should not write zero length strings. (#7806)
---
io.c | 40 ++++++++++++++++++++++++----------------
test/fiber/test_io.rb | 28 ++++++++++++++++++++++++++++
2 files changed, 52 insertions(+), 16 deletions(-)
| -rw-r--r-- | io.c | 40 | ||||
| -rw-r--r-- | test/fiber/test_io.rb | 28 | ||||
| -rw-r--r-- | version.h | 2 |
3 files changed, 53 insertions, 17 deletions
@@ -1320,14 +1320,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); } } @@ -2034,7 +2035,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) { @@ -8898,7 +8899,6 @@ 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. */ @@ -8906,22 +8906,30 @@ rb_io_puts(int argc, const VALUE *argv, VALUE out) 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); } diff --git a/test/fiber/test_io.rb b/test/fiber/test_io.rb index de88745e57..c1ad56a8cf 100644 --- a/test/fiber/test_io.rb +++ b/test/fiber/test_io.rb @@ -170,6 +170,34 @@ class TestFiberIO < Test::Unit::TestCase 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) @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 2 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 96 +#define RUBY_PATCHLEVEL 97 #include "ruby/version.h" #include "ruby/internal/abi.h" |
