summaryrefslogtreecommitdiff
path: root/string.c
diff options
context:
space:
mode:
authorKunshan Wang <[email protected]>2023-08-03 20:35:22 +0800
committerPeter Zhu <[email protected]>2023-08-03 14:52:44 -0400
commit132f097149af36cb77308d9fe1c1a94940ab2089 (patch)
tree420790b52878fdb96585416647cea2277e00ab44 /string.c
parentb35a2223486c80e496c0c678c1e3950be5086320 (diff)
No computing embed_capa_max in str_subseq
Fix str_subseq so that it does not attempt to predict the size of the object returned by str_alloc_heap.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/8165
Diffstat (limited to 'string.c')
-rw-r--r--string.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/string.c b/string.c
index 0a5a81c3e0..d3ebca1d8d 100644
--- a/string.c
+++ b/string.c
@@ -2732,15 +2732,30 @@ str_subseq(VALUE str, long beg, long len)
{
VALUE str2;
- const long rstring_embed_capa_max = ((sizeof(struct RString) - offsetof(struct RString, as.embed.ary)) / sizeof(char)) - 1;
+ assert(beg >= 0);
+ assert(len >= 0);
+ assert(beg+len <= RSTRING_LEN(str));
- if (!SHARABLE_SUBSTRING_P(beg, len, RSTRING_LEN(str)) ||
- len <= rstring_embed_capa_max) {
+ const int termlen = TERM_LEN(str);
+ if (!SHARABLE_SUBSTRING_P(beg, len, RSTRING_LEN(str))) {
str2 = rb_str_new(RSTRING_PTR(str) + beg, len);
RB_GC_GUARD(str);
+ return str2;
+ }
+
+ str2 = str_alloc_heap(rb_cString);
+ if (str_embed_capa(str2) >= len + termlen) {
+ char *ptr2 = RSTRING(str2)->as.embed.ary;
+ STR_SET_EMBED(str2);
+ memcpy(ptr2, RSTRING_PTR(str) + beg, len);
+ TERM_FILL(ptr2+len, termlen);
+
+ STR_SET_LEN(str2, len);
+ RB_GC_GUARD(str);
}
else {
- str2 = str_new_shared(rb_cString, str);
+ str_replace_shared(str2, str);
+ assert(!STR_EMBED_P(str2));
ENC_CODERANGE_CLEAR(str2);
RSTRING(str2)->as.heap.ptr += beg;
if (RSTRING_LEN(str2) > len) {