Skip to content

Commit 95c1194

Browse files
committed
Copy from the relocated string
When ungetting the string same as the same buffer string, extending the buffer can move the pointer in the argument. Reported by manun Manu (manun) at https://hackerone.com/reports/2805165.
1 parent ef03f93 commit 95c1194

File tree

2 files changed

+37
-9
lines changed

2 files changed

+37
-9
lines changed

ext/stringio/stringio.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,18 @@ strio_extend(struct StringIO *ptr, long pos, long len)
930930
}
931931
}
932932

933+
static void
934+
strio_unget_string(struct StringIO *ptr, VALUE c)
935+
{
936+
const char *cp = NULL;
937+
long cl = RSTRING_LEN(c);
938+
if (cl > 0) {
939+
if (c != ptr->string) cp = RSTRING_PTR(c);
940+
strio_unget_bytes(ptr, cp, cl);
941+
RB_GC_GUARD(c);
942+
}
943+
}
944+
933945
/*
934946
* call-seq:
935947
* ungetc(character) -> nil
@@ -967,8 +979,7 @@ strio_ungetc(VALUE self, VALUE c)
967979
if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
968980
c = rb_str_conv_enc(c, enc2, enc);
969981
}
970-
strio_unget_bytes(ptr, RSTRING_PTR(c), RSTRING_LEN(c));
971-
RB_GC_GUARD(c);
982+
strio_unget_string(ptr, c);
972983
return Qnil;
973984
}
974985
}
@@ -995,13 +1006,8 @@ strio_ungetbyte(VALUE self, VALUE c)
9951006
strio_unget_bytes(ptr, &cc, 1);
9961007
}
9971008
else {
998-
long cl;
9991009
StringValue(c);
1000-
cl = RSTRING_LEN(c);
1001-
if (cl > 0) {
1002-
strio_unget_bytes(ptr, RSTRING_PTR(c), cl);
1003-
RB_GC_GUARD(c);
1004-
}
1010+
strio_unget_string(ptr, c);
10051011
}
10061012
return Qnil;
10071013
}
@@ -1032,7 +1038,7 @@ strio_unget_bytes(struct StringIO *ptr, const char *cp, long cl)
10321038
if (rest > cl) memset(s + len, 0, rest - cl);
10331039
pos -= cl;
10341040
}
1035-
memcpy(s + pos, cp, cl);
1041+
memcpy(s + pos, (cp ? cp : s), cl);
10361042
ptr->pos = pos;
10371043
return Qnil;
10381044
}

test/stringio/test_stringio.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,17 @@ def test_ungetc_fill
842842
assert_match(/\Ab+\z/, s.string)
843843
end
844844

845+
def test_ungetc_same_string
846+
s = StringIO.new("abc" * 30)
847+
s.ungetc(s.string)
848+
assert_match(/\A(?:abc){60}\z/, s.string)
849+
850+
s = StringIO.new("abc" * 30)
851+
s.pos = 70 # ("abc".size * 30 - 70).divmod(3) == [6, 2]
852+
s.ungetc(s.string)
853+
assert_match(/\A(?:abc){30}bc(?:abc){6}\z/, s.string)
854+
end
855+
845856
def test_ungetbyte_pos
846857
b = '\\b00010001 \\B00010001 \\b1 \\B1 \\b000100011'
847858
s = StringIO.new( b )
@@ -876,6 +887,17 @@ def test_ungetbyte_fill
876887
assert_match(/\Ab+\z/, s.string)
877888
end
878889

890+
def test_ungetbyte_same_string
891+
s = StringIO.new("abc" * 30)
892+
s.ungetc(s.string)
893+
assert_match(/\A(?:abc){60}\z/, s.string)
894+
895+
s = StringIO.new("abc" * 30)
896+
s.pos = 70 # ("abc".size * 30 - 70).divmod(3) == [6, 2]
897+
s.ungetbyte(s.string)
898+
assert_match(/\A(?:abc){30}bc(?:abc){6}\z/, s.string)
899+
end
900+
879901
def test_frozen
880902
s = StringIO.new
881903
s.freeze

0 commit comments

Comments
 (0)