Skip to content

Commit

Permalink
merge revision(s) 6b66b5f: [Backport #19902]
Browse files Browse the repository at this point in the history
	[Bug #19902] Update the coderange regarding the changed region

	---
	 ext/-test-/string/set_len.c       | 10 ++++++++++
	 string.c                          | 27 +++++++++++++++++++++++++++
	 test/-ext-/string/test_set_len.rb | 29 +++++++++++++++++++++++++++++
	 3 files changed, 66 insertions(+)
  • Loading branch information
nagachika committed Sep 30, 2023
1 parent 128d872 commit ddbab4f
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 1 deletion.
10 changes: 10 additions & 0 deletions ext/-test-/string/set_len.c
Expand Up @@ -7,8 +7,18 @@ bug_str_set_len(VALUE str, VALUE len)
return str;
}

static VALUE
bug_str_append(VALUE str, VALUE addendum)
{
StringValue(addendum);
rb_str_modify_expand(str, RSTRING_LEN(addendum));
memcpy(RSTRING_END(str), RSTRING_PTR(addendum), RSTRING_LEN(addendum));
return str;
}

void
Init_string_set_len(VALUE klass)
{
rb_define_method(klass, "set_len", bug_str_set_len, 1);
rb_define_method(klass, "append", bug_str_append, 1);
}
27 changes: 27 additions & 0 deletions string.c
Expand Up @@ -3029,6 +3029,33 @@ rb_str_set_len(VALUE str, long len)
if (len > (capa = (long)str_capacity(str, termlen)) || len < 0) {
rb_bug("probable buffer overflow: %ld for %ld", len, capa);
}

int cr = ENC_CODERANGE(str);
if (cr == ENC_CODERANGE_UNKNOWN) {
/* Leave unknown. */
}
else if (len > RSTRING_LEN(str)) {
if (ENC_CODERANGE_CLEAN_P(cr)) {
/* Update the coderange regarding the extended part. */
const char *const prev_end = RSTRING_END(str);
const char *const new_end = RSTRING_PTR(str) + len;
rb_encoding *enc = rb_enc_get(str);
rb_str_coderange_scan_restartable(prev_end, new_end, enc, &cr);
ENC_CODERANGE_SET(str, cr);
}
else if (cr == ENC_CODERANGE_BROKEN) {
/* May be valid now, by appended part. */
ENC_CODERANGE_SET(str, ENC_CODERANGE_UNKNOWN);
}
}
else if (len < RSTRING_LEN(str)) {
if (cr != ENC_CODERANGE_7BIT) {
/* ASCII-only string is keeping after truncated. Valid
* and broken may be invalid or valid, leave unknown. */
ENC_CODERANGE_SET(str, ENC_CODERANGE_UNKNOWN);
}
}

STR_SET_LEN(str, len);
TERM_FILL(&RSTRING_PTR(str)[len], termlen);
}
Expand Down
29 changes: 29 additions & 0 deletions test/-ext-/string/test_set_len.rb
Expand Up @@ -34,4 +34,33 @@ def test_capacity_equals_to_new_size
assert_equal 128, Bug::String.capacity(str)
assert_equal 127, str.set_len(127).bytesize, bug12757
end

def test_coderange_after_append
u = -"\u3042"
str = Bug::String.new(encoding: Encoding::UTF_8)
bsize = u.bytesize
str.append(u)
assert_equal 0, str.bytesize
str.set_len(bsize)
assert_equal bsize, str.bytesize
assert_predicate str, :valid_encoding?
assert_not_predicate str, :ascii_only?
assert_equal u, str
end

def test_coderange_after_trunc
u = -"\u3042"
bsize = u.bytesize
str = Bug::String.new(u)
str.set_len(bsize - 1)
assert_equal bsize - 1, str.bytesize
assert_not_predicate str, :valid_encoding?
assert_not_predicate str, :ascii_only?
str.append(u.byteslice(-1))
str.set_len(bsize)
assert_equal bsize, str.bytesize
assert_predicate str, :valid_encoding?
assert_not_predicate str, :ascii_only?
assert_equal u, str
end
end
2 changes: 1 addition & 1 deletion version.h
Expand Up @@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 2
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
#define RUBY_PATCHLEVEL 124
#define RUBY_PATCHLEVEL 125

#include "ruby/version.h"
#include "ruby/internal/abi.h"
Expand Down

0 comments on commit ddbab4f

Please sign in to comment.