Compare commits

...

2 Commits

Author SHA1 Message Date
Yukihiro "Matz" Matsumoto 31ea49319a Merge pull request #6876 from dkgkdfg65/backport/7dfd560d-stable
[stable] backport: cap IO#puts recursion depth on cyclic arrays (mruby-io)
2026-05-31 08:18:35 +09:00
Yukihiro "Matz" Matsumoto 3533335aa0 mruby-io: cap puts recursion depth to prevent C stack overflow
io_puts_ary recursed unconditionally on nested arrays. For cyclic
arrays (a = []; a << a; puts a) or pathologically deep arrays,
this caused a C stack overflow.

Add a depth cap (IO_PUTS_MAX_DEPTH = 16); on overflow, write
"[...]\n" and return, matching CRuby's behavior on cycles. The
pattern mirrors mruby-set's MAX_NESTED_DEPTH for the same problem
shape (pure C recursion not dispatched as a Ruby method).

Reported by OSS-Fuzz (clusterfuzz testcase 6233530857488384).

Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit 7dfd560df8)
2026-05-30 01:31:48 +08:00
+13 -3
View File
@@ -992,10 +992,20 @@ io_puts_str(mrb_state *mrb, int fd, mrb_value str)
} }
} }
/* Maximum nesting depth for puts with arrays; guards against cyclic and
pathologically deep arrays causing C stack overflow. */
#define IO_PUTS_MAX_DEPTH 16
/* Recursive helper for puts with arrays */ /* Recursive helper for puts with arrays */
static void static void
io_puts_ary(mrb_state *mrb, int fd, mrb_value ary) io_puts_ary(mrb_state *mrb, int fd, mrb_value ary, int depth)
{ {
if (depth >= IO_PUTS_MAX_DEPTH) {
mrb_value mark = mrb_str_new_lit(mrb, "[...]\n");
fd_write(mrb, fd, mark);
return;
}
mrb_int len = RARRAY_LEN(ary); mrb_int len = RARRAY_LEN(ary);
if (len == 0) { if (len == 0) {
@@ -1008,7 +1018,7 @@ io_puts_ary(mrb_state *mrb, int fd, mrb_value ary)
for (mrb_int i = 0; i < len; i++) { for (mrb_int i = 0; i < len; i++) {
mrb_value elem = RARRAY_PTR(ary)[i]; mrb_value elem = RARRAY_PTR(ary)[i];
if (mrb_array_p(elem)) { if (mrb_array_p(elem)) {
io_puts_ary(mrb, fd, elem); /* Recursive call for nested arrays */ io_puts_ary(mrb, fd, elem, depth + 1);
} }
else { else {
io_puts_str(mrb, fd, elem); io_puts_str(mrb, fd, elem);
@@ -1040,7 +1050,7 @@ io_puts(mrb_state *mrb, mrb_value io)
for (mrb_int i = 0; i < argc; i++) { for (mrb_int i = 0; i < argc; i++) {
mrb_value arg = argv[i]; mrb_value arg = argv[i];
if (mrb_array_p(arg)) { if (mrb_array_p(arg)) {
io_puts_ary(mrb, fd, arg); io_puts_ary(mrb, fd, arg, 0);
} }
else { else {
io_puts_str(mrb, fd, arg); io_puts_str(mrb, fd, arg);