[ruby/stringio] Fix SEGV at read/pread on null StringIO

113dd5a55e
This commit is contained in:
Nobuyoshi Nakada 2025-08-09 19:44:26 +09:00 committed by git
parent 23c0113932
commit 31f2d8990d
2 changed files with 29 additions and 9 deletions

View file

@ -203,6 +203,18 @@ check_modifiable(struct StringIO *ptr)
} }
} }
static inline bool
outside_p(struct StringIO *ptr, long pos)
{
return NIL_P(ptr->string) || pos >= RSTRING_LEN(ptr->string);
}
static inline bool
eos_p(struct StringIO *ptr)
{
return outside_p(ptr, ptr->pos);
}
static VALUE static VALUE
strio_s_allocate(VALUE klass) strio_s_allocate(VALUE klass)
{ {
@ -628,9 +640,8 @@ static struct StringIO *
strio_to_read(VALUE self) strio_to_read(VALUE self)
{ {
struct StringIO *ptr = readable(self); struct StringIO *ptr = readable(self);
if (NIL_P(ptr->string)) return NULL; if (eos_p(ptr)) return NULL;
if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr; return ptr;
return NULL;
} }
/* /*
@ -910,7 +921,7 @@ strio_getc(VALUE self)
int len; int len;
char *p; char *p;
if (NIL_P(str) || pos >= RSTRING_LEN(str)) { if (eos_p(ptr)) {
return Qnil; return Qnil;
} }
p = RSTRING_PTR(str)+pos; p = RSTRING_PTR(str)+pos;
@ -931,7 +942,7 @@ strio_getbyte(VALUE self)
{ {
struct StringIO *ptr = readable(self); struct StringIO *ptr = readable(self);
int c; int c;
if (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string)) { if (eos_p(ptr)) {
return Qnil; return Qnil;
} }
c = RSTRING_PTR(ptr->string)[ptr->pos++]; c = RSTRING_PTR(ptr->string)[ptr->pos++];
@ -1609,10 +1620,9 @@ strio_read(int argc, VALUE *argv, VALUE self)
if (len < 0) { if (len < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len); rb_raise(rb_eArgError, "negative length %ld given", len);
} }
if (len > 0 && if (eos_p(ptr)) {
(NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string))) {
if (!NIL_P(str)) rb_str_resize(str, 0); if (!NIL_P(str)) rb_str_resize(str, 0);
return Qnil; return len > 0 ? Qnil : rb_str_new(0, 0);
} }
binary = 1; binary = 1;
break; break;
@ -1688,7 +1698,7 @@ strio_pread(int argc, VALUE *argv, VALUE self)
struct StringIO *ptr = readable(self); struct StringIO *ptr = readable(self);
if (offset >= RSTRING_LEN(ptr->string)) { if (outside_p(ptr, offset)) {
rb_eof_error(); rb_eof_error();
} }

View file

@ -70,6 +70,16 @@ class TestStringIO < Test::Unit::TestCase
assert_nil io.getc assert_nil io.getc
end end
def test_pread_null
io = StringIO.new(nil)
assert_raise(EOFError) { io.pread(1, 0) }
end
def test_read_null
io = StringIO.new(nil)
assert_equal "", io.read(0)
end
def test_seek_null def test_seek_null
io = StringIO.new(nil) io = StringIO.new(nil)
assert_equal(0, io.seek(0, IO::SEEK_SET)) assert_equal(0, io.seek(0, IO::SEEK_SET))