summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2023-07-22 13:03:22 +0900
committernagachika <nagachika@ruby-lang.org>2023-07-22 13:03:22 +0900
commitea89527a76a84741463c304246db2dd3a5df845b (patch)
treee211be19a5741aef1a466a23037de21df9487d06
parent465eb7418d7ed91f5f0c75da77765c7f5ef8354f (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.c40
-rw-r--r--test/fiber/test_io.rb28
-rw-r--r--version.h2
3 files changed, 53 insertions, 17 deletions
diff --git a/io.c b/io.c
index 2e51a46635..4caf771b05 100644
--- a/io.c
+++ b/io.c
@@ -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)
diff --git a/version.h b/version.h
index 3931a17d31..d6859e62ee 100644
--- a/version.h
+++ b/version.h
@@ -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"