From 23c0113932407abccddbc6ee5b297d38d2d2bb9c Mon Sep 17 00:00:00 2001 From: koh-sh <34917718+koh-sh@users.noreply.github.com> Date: Sat, 9 Aug 2025 18:30:17 +0900 Subject: [PATCH] [ruby/stringio] fix: prevent segfault in StringIO#seek with SEEK_END on null device (https://github.com/ruby/stringio/pull/137) Fixes segmentation fault when calling `seek` with `SEEK_END` on null device StringIO created by `StringIO.new(nil)`. ```bash ruby -e "require 'stringio'; StringIO.new(nil).seek(0, IO::SEEK_END)" ``` I tested with below versions. ```bash [koh@Kohs-MacBook-Pro] ~ % ruby -v;gem info stringio;sw_vers ruby 3.4.5 (2025-07-16 revision https://github.com/ruby/stringio/commit/20cda200d3) +PRISM [arm64-darwin24] *** LOCAL GEMS *** stringio (3.1.2) Authors: Nobu Nakada, Charles Oliver Nutter Homepage: https://github.com/ruby/stringio Licenses: Ruby, BSD-2-Clause Installed at (default): /Users/koh/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0 Pseudo IO on String ProductName: macOS ProductVersion: 15.5 BuildVersion: 24F74 [koh@Kohs-MacBook-Pro] ~ % ``` https://github.com/ruby/stringio/commit/9399747bf9 --- ext/stringio/stringio.c | 6 +++++- test/stringio/test_stringio.rb | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c index 3003939e10..d9beb25434 100644 --- a/ext/stringio/stringio.c +++ b/ext/stringio/stringio.c @@ -837,7 +837,11 @@ strio_seek(int argc, VALUE *argv, VALUE self) offset = ptr->pos; break; case 2: - offset = RSTRING_LEN(ptr->string); + if (NIL_P(ptr->string)) { + offset = 0; + } else { + offset = RSTRING_LEN(ptr->string); + } break; default: error_inval("invalid whence"); diff --git a/test/stringio/test_stringio.rb b/test/stringio/test_stringio.rb index 002b946b6f..4c9cf37425 100644 --- a/test/stringio/test_stringio.rb +++ b/test/stringio/test_stringio.rb @@ -70,6 +70,16 @@ class TestStringIO < Test::Unit::TestCase assert_nil io.getc end + def test_seek_null + io = StringIO.new(nil) + assert_equal(0, io.seek(0, IO::SEEK_SET)) + assert_equal(0, io.pos) + assert_equal(0, io.seek(0, IO::SEEK_CUR)) + assert_equal(0, io.pos) + assert_equal(0, io.seek(0, IO::SEEK_END)) # This should not segfault + assert_equal(0, io.pos) + end + def test_truncate io = StringIO.new("") io.puts "abc"