Skip to content

Commit 7dfd560

Browse files
matzclaude
andcommitted
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 <[email protected]>
1 parent 8a73faf commit 7dfd560

1 file changed

Lines changed: 13 additions & 3 deletions

File tree

  • mrbgems/mruby-io/src

mrbgems/mruby-io/src/io.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -992,10 +992,20 @@ io_puts_str(mrb_state *mrb, int fd, mrb_value str)
992992
}
993993
}
994994

995+
/* Maximum nesting depth for puts with arrays; guards against cyclic and
996+
pathologically deep arrays causing C stack overflow. */
997+
#define IO_PUTS_MAX_DEPTH 16
998+
995999
/* Recursive helper for puts with arrays */
9961000
static void
997-
io_puts_ary(mrb_state *mrb, int fd, mrb_value ary)
1001+
io_puts_ary(mrb_state *mrb, int fd, mrb_value ary, int depth)
9981002
{
1003+
if (depth >= IO_PUTS_MAX_DEPTH) {
1004+
mrb_value mark = mrb_str_new_lit(mrb, "[...]\n");
1005+
fd_write(mrb, fd, mark);
1006+
return;
1007+
}
1008+
9991009
mrb_int len = RARRAY_LEN(ary);
10001010

10011011
if (len == 0) {
@@ -1008,7 +1018,7 @@ io_puts_ary(mrb_state *mrb, int fd, mrb_value ary)
10081018
for (mrb_int i = 0; i < len; i++) {
10091019
mrb_value elem = RARRAY_PTR(ary)[i];
10101020
if (mrb_array_p(elem)) {
1011-
io_puts_ary(mrb, fd, elem); /* Recursive call for nested arrays */
1021+
io_puts_ary(mrb, fd, elem, depth + 1);
10121022
}
10131023
else {
10141024
io_puts_str(mrb, fd, elem);
@@ -1040,7 +1050,7 @@ io_puts(mrb_state *mrb, mrb_value io)
10401050
for (mrb_int i = 0; i < argc; i++) {
10411051
mrb_value arg = argv[i];
10421052
if (mrb_array_p(arg)) {
1043-
io_puts_ary(mrb, fd, arg);
1053+
io_puts_ary(mrb, fd, arg, 0);
10441054
}
10451055
else {
10461056
io_puts_str(mrb, fd, arg);

0 commit comments

Comments
 (0)