Merge pull request #5986 from dearblue/bytesplice

Fix bugs in `String#bytesplice`
This commit is contained in:
Yukihiro "Matz" Matsumoto
2023-04-17 07:17:00 +09:00
committed by GitHub
2 changed files with 45 additions and 29 deletions
+15 -5
View File
@@ -2947,16 +2947,25 @@ static mrb_value
str_bytesplice(mrb_state *mrb, mrb_value str, mrb_int idx1, mrb_int len1, mrb_value replace, mrb_int idx2, mrb_int len2)
{
struct RString *s = RSTRING(str);
if (RSTR_LEN(s) < idx1 || RSTRING_LEN(replace) < idx2) {
if (idx1 < 0) {
idx1 += RSTR_LEN(s);
}
if (idx2 < 0) {
idx2 += RSTRING_LEN(replace);
}
if (RSTR_LEN(s) < idx1 || idx1 < 0 || RSTRING_LEN(replace) < idx2 || idx2 < 0) {
mrb_raise(mrb, E_INDEX_ERROR, "index out of string");
}
if (RSTR_LEN(s) <= idx1+len1) {
if (len1 < 0 || len2 < 0) {
mrb_raise(mrb, E_INDEX_ERROR, "negative length");
}
mrb_int n;
if (mrb_int_add_overflow(idx1, len1, &n) || RSTR_LEN(s) < n) {
len1 = RSTR_LEN(s) - idx1;
}
if (RSTRING_LEN(replace) <= idx2+len2) {
if (mrb_int_add_overflow(idx2, len2, &n) || RSTRING_LEN(replace) < n) {
len2 = RSTRING_LEN(replace) - idx2;
}
if (len2 == 0) return replace;
mrb_str_modify(mrb, s);
if (len1 >= len2) {
memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2);
@@ -2971,7 +2980,7 @@ str_bytesplice(mrb_state *mrb, mrb_value str, mrb_int idx1, mrb_int len1, mrb_va
memmove(RSTR_PTR(s)+idx1+len2, RSTR_PTR(s)+idx1+len1, slen-(idx1+len1));
memmove(RSTR_PTR(s)+idx1, RSTRING_PTR(replace)+idx2, len2);
}
return replace;
return str;
}
/*
@@ -3006,6 +3015,7 @@ mrb_str_bytesplice(mrb_state *mrb, mrb_value str)
mrb_get_args(mrb, "iiS", &idx1, &len1, &replace);
return str_bytesplice(mrb, str, idx1, len1, replace, 0, RSTRING_LEN(replace));
}
mrb_ensure_string_type(mrb, replace);
if (mrb_range_beg_len(mrb, range1, &idx1, &len1, RSTRING_LEN(str), FALSE) != MRB_RANGE_OK) break;
if (mrb_range_beg_len(mrb, range2, &idx2, &len2, RSTRING_LEN(replace), FALSE) != MRB_RANGE_OK) break;
return str_bytesplice(mrb, str, idx1, len1, replace, idx2, len2);
+30 -24
View File
@@ -902,62 +902,68 @@ end
assert('String#bytesplice') do
# range, replace (len1=len2)
a = "0123456789"
assert_equal "ab", a.bytesplice(1..2, "ab")
assert_equal "0ab3456789", a
assert_equal "0ab3456789", a.bytesplice(1..2, "ab")
# range, replace (len1>len2)
a = "0123456789"
assert_equal "ab", a.bytesplice(1..3, "ab")
assert_equal "0ab456789", a
assert_equal "0ab456789", a.bytesplice(1..3, "ab")
# range, replace (len1<len2)
a = "0123456789"
assert_equal "ab", a.bytesplice(1..1, "ab")
assert_equal "0ab23456789", a
assert_equal "0ab23456789", a.bytesplice(1..1, "ab")
# idx, len, replace (len1=len2)
a = "0123456789"
assert_equal "ab", a.bytesplice(1, 2, "ab")
assert_equal "0ab3456789", a
assert_equal "0ab3456789", a.bytesplice(1, 2, "ab")
# idx, len, replace (len1>len2)
a = "0123456789"
assert_equal "ab", a.bytesplice(1, 3, "ab")
assert_equal "0ab456789", a
assert_equal "0ab456789", a.bytesplice(1, 3, "ab")
# idx, len, replace (len1<len2)
a = "0123456789"
assert_equal "ab", a.bytesplice(1, 1, "ab")
assert_equal "0ab23456789", a
assert_equal "0ab23456789", a.bytesplice(1, 1, "ab")
b = "abcdefg"
# range, replace, range (len1=len2)
a = "0123456789"
assert_equal b, a.bytesplice(1..2, b, 0..1)
assert_equal "0ab3456789", a
assert_equal "0ab3456789", a.bytesplice(1..2, b, 0..1)
# range, replace, range (len1>len2)
a = "0123456789"
assert_equal b, a.bytesplice(1..3, b, 1..2)
assert_equal "0bc456789", a
assert_equal "0bc456789", a.bytesplice(1..3, b, 1..2)
# range, replace, range (len1<len2)
a = "0123456789"
assert_equal b, a.bytesplice(1..1, b, 2..3)
assert_equal "0cd23456789", a
assert_equal "0cd23456789", a.bytesplice(1..1, b, 2..3)
# idx, len, replace, idx, len (len1=len2)
a = "0123456789"
assert_equal b, a.bytesplice(1, 2, b, 0, 2)
assert_equal "0ab3456789", a
assert_equal "0ab3456789", a.bytesplice(1, 2, b, 0, 2)
# idx, len, replace, idx, len (len1>len2)
a = "0123456789"
assert_equal b, a.bytesplice(1, 3, b, 1, 2)
assert_equal "0bc456789", a
assert_equal "0bc456789", a.bytesplice(1, 3, b, 1, 2)
# idx, len, replace, idx, len (len1<len2)
a = "0123456789"
assert_equal b, a.bytesplice(1, 1, b, 2, 2)
assert_equal "0cd23456789", a
assert_equal "0cd23456789", a.bytesplice(1, 1, b, 2, 2)
# check the object type to replace
assert_raise(TypeError) { "0123456789".bytesplice(1, 1, Object.new) }
# check the overflow to index and length (to be pass without crash)
assert_nothing_raised { "0123456789".bytesplice(8, ~(-1 << 31), "ab") } # for MRB_INT32
assert_nothing_raised { begin; "0123456789".bytesplice(8, ~(-1 << 63), "ab"); rescue ArgumentError, RangeError; end } # for MRB_INT64
# check the negative index
assert_equal "0ab3456789", "0123456789".bytesplice(-9, 2, "ab")
assert_equal "ab23456789", "0123456789".bytesplice(-10, 2, "ab")
assert_raise(IndexError) { "0123456789".bytesplice(-11, 2, "ab") }
# check the negative length
assert_raise(IndexError) { "0123456789".bytesplice(3, -4, "ab") }
# with an empty string
assert_equal "012789", "0123456789".bytesplice(3, 4, "")
end