Skip to content

Commit 18ba026

Browse files
authored
Merge pull request #6780 from mruby/fix/string-prepend-overflow
2 parents 4eb4884 + af6f23d commit 18ba026

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

mrbgems/mruby-string-ext/src/string.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2201,15 +2201,27 @@ str_prepend(mrb_state *mrb, mrb_value self)
22012201

22022202
char *p = RSTRING_PTR(self);
22032203

2204-
/* Move original content to the end */
2204+
/* Move original content to the end. The original self data now lives
2205+
at p + total_prepend_len, which we use as the source for any
2206+
self-referencing arguments (e.g., s.prepend(s, s)) to avoid reading
2207+
data that has already been overwritten by earlier copies. */
22052208
memmove(p + total_prepend_len, p, self_len);
22062209

22072210
/* Copy prepended strings in order */
22082211
mrb_int offset = 0;
22092212
for (mrb_int i = 0; i < argc; i++) {
2210-
mrb_int arg_len = RSTRING_LEN(argv[i]);
2213+
const char *src;
2214+
mrb_int arg_len;
2215+
if (mrb_obj_eq(mrb, self, argv[i])) {
2216+
src = p + total_prepend_len;
2217+
arg_len = self_len;
2218+
}
2219+
else {
2220+
src = RSTRING_PTR(argv[i]);
2221+
arg_len = RSTRING_LEN(argv[i]);
2222+
}
22112223
if (arg_len > 0) {
2212-
memcpy(p + offset, RSTRING_PTR(argv[i]), arg_len);
2224+
memcpy(p + offset, src, arg_len);
22132225
offset += arg_len;
22142226
}
22152227
}

mrbgems/mruby-string-ext/test/string.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,21 @@ def assert_upto(exp, receiver, *args)
492492
g = "world"
493493
assert_equal "hello world", g.prepend("", "hello ", "")
494494
assert_equal "hello world", g
495+
496+
# Self-referencing arguments (GHSA-3hgj-g76g-878c)
497+
h = "A" * 100
498+
h.prepend(h, h)
499+
assert_equal 300, h.length
500+
assert_equal "A" * 300, h
501+
502+
# Mixed self-reference and literal
503+
i = "AB"
504+
i.prepend("XYZ", i)
505+
assert_equal "XYZABAB", i
506+
507+
j = "AB"
508+
j.prepend(j, "X", j)
509+
assert_equal "ABXABAB", j
495510
end
496511

497512
assert('String#ljust') do

0 commit comments

Comments
 (0)