Skip to content

Commit 113dd5a

Browse files
committed
Fix SEGV at read/pread on null StringIO
1 parent 9399747 commit 113dd5a

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

ext/java/org/jruby/ext/stringio/StringIO.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -655,8 +655,12 @@ public IRubyObject eof(ThreadContext context) {
655655
}
656656

657657
private boolean isEndOfString() {
658+
return isOutside(ptr.pos);
659+
}
660+
661+
private boolean isOutside(int pos) {
658662
StringIOData ptr = getPtr();
659-
return ptr.string == null || ptr.pos >= ptr.string.size();
663+
return ptr.string == null || pos >= ptr.string.size();
660664
}
661665

662666
@JRubyMethod(name = "getc")
@@ -1107,9 +1111,9 @@ private IRubyObject readCommon(ThreadContext context, int argc, IRubyObject arg0
11071111
if (len < 0) {
11081112
throw runtime.newArgumentError("negative length " + len + " given");
11091113
}
1110-
if (len > 0 && isEndOfString()) {
1114+
if (isEndOfString()) {
11111115
if (!str.isNil()) ((RubyString) str).resize(0);
1112-
return context.nil;
1116+
return len > 0 ? context.nil : runtime.newString();
11131117
}
11141118
binary = true;
11151119
break;
@@ -1224,8 +1228,7 @@ private RubyString preadCommon(ThreadContext context, int argc, IRubyObject arg0
12241228
throw runtime.newErrnoEINVALError("pread: Invalid offset argument");
12251229
}
12261230

1227-
RubyString myString = ptr.string;
1228-
if (offset >= myString.size()) {
1231+
if (isOutside(offset)) {
12291232
throw context.runtime.newEOFError();
12301233
}
12311234

@@ -1234,6 +1237,7 @@ private RubyString preadCommon(ThreadContext context, int argc, IRubyObject arg0
12341237
}
12351238

12361239
string = (RubyString) str;
1240+
RubyString myString = ptr.string;
12371241
int rest = myString.size() - offset;
12381242
if (len > rest) len = rest;
12391243
string.resize(len);

ext/stringio/stringio.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,18 @@ check_modifiable(struct StringIO *ptr)
203203
}
204204
}
205205

206+
static inline bool
207+
outside_p(struct StringIO *ptr, long pos)
208+
{
209+
return NIL_P(ptr->string) || pos >= RSTRING_LEN(ptr->string);
210+
}
211+
212+
static inline bool
213+
eos_p(struct StringIO *ptr)
214+
{
215+
return outside_p(ptr, ptr->pos);
216+
}
217+
206218
static VALUE
207219
strio_s_allocate(VALUE klass)
208220
{
@@ -628,9 +640,8 @@ static struct StringIO *
628640
strio_to_read(VALUE self)
629641
{
630642
struct StringIO *ptr = readable(self);
631-
if (NIL_P(ptr->string)) return NULL;
632-
if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr;
633-
return NULL;
643+
if (eos_p(ptr)) return NULL;
644+
return ptr;
634645
}
635646

636647
/*
@@ -910,7 +921,7 @@ strio_getc(VALUE self)
910921
int len;
911922
char *p;
912923

913-
if (NIL_P(str) || pos >= RSTRING_LEN(str)) {
924+
if (eos_p(ptr)) {
914925
return Qnil;
915926
}
916927
p = RSTRING_PTR(str)+pos;
@@ -931,7 +942,7 @@ strio_getbyte(VALUE self)
931942
{
932943
struct StringIO *ptr = readable(self);
933944
int c;
934-
if (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string)) {
945+
if (eos_p(ptr)) {
935946
return Qnil;
936947
}
937948
c = RSTRING_PTR(ptr->string)[ptr->pos++];
@@ -1609,10 +1620,9 @@ strio_read(int argc, VALUE *argv, VALUE self)
16091620
if (len < 0) {
16101621
rb_raise(rb_eArgError, "negative length %ld given", len);
16111622
}
1612-
if (len > 0 &&
1613-
(NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string))) {
1623+
if (eos_p(ptr)) {
16141624
if (!NIL_P(str)) rb_str_resize(str, 0);
1615-
return Qnil;
1625+
return len > 0 ? Qnil : rb_str_new(0, 0);
16161626
}
16171627
binary = 1;
16181628
break;
@@ -1688,7 +1698,7 @@ strio_pread(int argc, VALUE *argv, VALUE self)
16881698

16891699
struct StringIO *ptr = readable(self);
16901700

1691-
if (offset >= RSTRING_LEN(ptr->string)) {
1701+
if (outside_p(ptr, offset)) {
16921702
rb_eof_error();
16931703
}
16941704

test/stringio/test_stringio.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ def test_null
7070
assert_nil io.getc
7171
end
7272

73+
def test_pread_null
74+
io = StringIO.new(nil)
75+
assert_raise(EOFError) { io.pread(1, 0) }
76+
end
77+
78+
def test_read_null
79+
io = StringIO.new(nil)
80+
assert_equal "", io.read(0)
81+
end
82+
7383
def test_seek_null
7484
io = StringIO.new(nil)
7585
assert_equal(0, io.seek(0, IO::SEEK_SET))

0 commit comments

Comments
 (0)