Allow sharing middlesubstring if the terminator is present

Sharing middle substrings have been behind a compilation flags for
a very long time, and it's unclear if we'll ever make it the default.

However, we can still share middle substrings without breaking the
zero-terminated contract if the source string happens to have the
necessary NUL characters at that specific offset.

This is the case for some file formats such as FlatBuffers, BSON keys
and a few others.
This commit is contained in:
Jean Boussier committed 2026-04-07 10:26:25 +02:00
1 parent 13926009ba
commit fcd210086c
2 files changed
+42 -15
Notes: git 2026-04-07 08:26:56 +00:00

No files matched your search

+21 -15
View File
@@ -198,15 +198,30 @@ VALUE rb_cSymbol;
#define STR_ENC_GET(str) get_encoding(str)
static inline bool
zero_filled(const char *s, int n)
{
for (; n > 0; --n) {
if (*s++) return false;
}
return true;
}
#if !defined SHARABLE_MIDDLE_SUBSTRING
# define SHARABLE_MIDDLE_SUBSTRING 0
#endif
#if !SHARABLE_MIDDLE_SUBSTRING
#define SHARABLE_SUBSTRING_P(beg, len, end) ((beg) + (len) == (end))
#else
#define SHARABLE_SUBSTRING_P(beg, len, end) 1
#endif
static inline bool
SHARABLE_SUBSTRING_P(VALUE str, long beg, long len)
{
#if SHARABLE_MIDDLE_SUBSTRING
return true;
#else
long end = beg + len;
long source_len = RSTRING_LEN(str);
return end == source_len || zero_filled(RSTRING_PTR(str) + end, TERM_LEN(str));
#endif
}
static inline long
str_embed_capa(VALUE str)
@@ -2810,15 +2825,6 @@ rb_string_value_ptr(volatile VALUE *ptr)
return RSTRING_PTR(str);
}
static int
zero_filled(const char *s, int n)
{
for (; n > 0; --n) {
if (*s++) return 0;
}
return 1;
}
static const char *
str_null_char(const char *s, long len, const int minlen, rb_encoding *enc)
{
@@ -3138,7 +3144,7 @@ str_subseq(VALUE str, long beg, long len)
RUBY_ASSERT(beg+len <= RSTRING_LEN(str));
const int termlen = TERM_LEN(str);
if (!SHARABLE_SUBSTRING_P(beg, len, RSTRING_LEN(str))) {
if (!SHARABLE_SUBSTRING_P(str, beg, len)) {
str2 = rb_enc_str_new(RSTRING_PTR(str) + beg, len, rb_str_enc_get(str));
if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) {
ENC_CODERANGE_SET(str2, ENC_CODERANGE_7BIT);
+21
View File
@@ -3461,6 +3461,27 @@ CODE
assert_equal(false, ("\u3042"*10).byteslice(0, 20).valid_encoding?, bug7954)
end
def test_shared_middle_string_terminator
ten = "0123456789"
hundred = ten * 10
str = "#{hundred}\0#{hundred}".freeze
require 'objspace'
substr = str.byteslice(0, hundred.bytesize)
assert_equal hundred, substr
assert_includes ObjectSpace.dump(substr), ' "shared":true,'
# Larger terminator
substr.force_encoding(Encoding::UTF_16BE)
assert_equal hundred.dup.force_encoding(Encoding::UTF_16BE), substr
refute_includes ObjectSpace.dump(substr), ' "shared":true,'
substr = str.byteslice(0, hundred.bytesize + 1)
assert_equal hundred + "\0", substr
refute_includes ObjectSpace.dump(substr), ' "shared":true,'
end
def test_unknown_string_option
str = nil
assert_nothing_raised(SyntaxError) do