From 4035e42a39abf8b70957809310ba5254ee773554 Mon Sep 17 00:00:00 2001 From: HASUMI Hitoshi Date: Fri, 22 Aug 2025 17:01:08 +0900 Subject: [PATCH] Fix uninitialized variable in io_gets causing segmentation fault This patch fixs a critical segmentation fault in `io_gets` function caused by an uninitialized limit variable. This bug may specifically heppen when: - MicroRuby with task scheduler, which I'm implementing, enabled ## Root Cause Analysis When `io_gets` is called without arguments (argc=0), the local variable `limit` remains uninitialized on the stack. I guess that this uninitialized memory often contains leftover heap addresses from previous stack frames. ### The problematic flow: 1. `mrb_get_args(mrb, "|o?i?", &rs, &rs_given, &limit, &limit_given)` with 0 arguments 2. `limit_given = FALSE` but limit contains garbage heap address 3. Looks like later processing truncates this address, creating invalid pointer 0xffff0000 4. This value gets pushed onto VM stack during string operations 5. Garbage collector attempts to mark 0xffff0000 as valid object pointer 6. SIGSEGV in mrb_gc_mark() at gc.c:748 ``` Program received signal SIGSEGV, Segmentation fault. 0x00005c8bebffa95c in mrb_gc_mark (mrb=0x5c8bec2836c8 , obj=0xffff0000) at .../gc.c:748 748 if (!is_white(obj)) return; #1 mark_context_stack (mrb=0x5c8bec2836c8 , c=0x5c8bec2b4a50 ) at .../gc.c:555 555 mrb_gc_mark(mrb, mrb_basic_ptr(v)); ``` ## Solution I couldn't figure out the exact mechanism of the issue. Anyway, initializing the limit variable to zero could prevent invalid garbage stack memory: ```c mrb_int limit = 0; // Explicit initialization ``` ## Files Changed - mrbgems/picoruby-mruby/lib/mruby/mrbgems/mruby-io/src/io.c --- mrbgems/mruby-io/src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 28c676763..d82eeb4a5 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -2072,7 +2072,7 @@ io_gets(mrb_state *mrb, mrb_value io) { mrb_value rs = mrb_nil_value(); mrb_bool rs_given = FALSE; /* newline break */ - mrb_int limit; + mrb_int limit = 0; mrb_bool limit_given = FALSE; /* no limit */ struct mrb_io *fptr = io_get_read_fptr(mrb, io); struct mrb_io_buf *buf = fptr->buf;