Skip to content

Commit

Permalink
Fix ascii_only? flag in strio_write (#77)
Browse files Browse the repository at this point in the history
Followup of #79

`rb_str_resize()` was changed by ruby/ruby@b0b9f72  .

```c
rb_str_resize(string, shorter) // clear ENC_CODERANGE in some case
rb_str_resize(string, longer) // does not clear ENC_CODERANGE anymore
```

```c
// rb_str_resize in string.c
if (slen > len && ENC_CODERANGE(str) != ENC_CODERANGE_7BIT) {
  ENC_CODERANGE_CLEAR(str);
}
```

I think this change is based on an assumption that appending null bytes
will not change flag `ascii_only?`.

`strio_extend()` will make the string longer if needed, and update the
flags correctly for appending null bytes.
Before `memmove()`, we need to `rb_str_modify()` because updated flags are not
updated for `memmove()`.
  • Loading branch information
tompng authored Jan 18, 2024
1 parent 8230552 commit b31a538
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 9 deletions.
10 changes: 1 addition & 9 deletions ext/stringio/stringio.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,9 +915,6 @@ strio_extend(struct StringIO *ptr, long pos, long len)
if (pos > olen)
MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen);
}
else {
rb_str_modify(ptr->string);
}
}

/*
Expand Down Expand Up @@ -1464,14 +1461,9 @@ strio_write(VALUE self, VALUE str)
}
}
else {
int cr0 = ENC_CODERANGE(ptr->string);
int cr = ENC_CODERANGE_UNKNOWN;
if (rb_enc_asciicompat(enc) && rb_enc_asciicompat(enc2)) {
cr = ENC_CODERANGE_AND(cr0, ENC_CODERANGE(str));
}
strio_extend(ptr, ptr->pos, len);
rb_str_modify(ptr->string);
memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len);
if (cr != cr0) ENC_CODERANGE_SET(ptr->string, cr);
}
RB_GC_GUARD(str);
ptr->pos += len;
Expand Down
6 changes: 6 additions & 0 deletions test/stringio/test_stringio.rb
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,12 @@ def test_coderange_after_overwrite
assert_predicate(s.string, :ascii_only?)
s.write "\u{431 43e 433 443 441}"
assert_not_predicate(s.string, :ascii_only?)

s = StringIO.new("\u{3042}")
s.rewind
assert_not_predicate(s.string, :ascii_only?)
s.write('aaaa')
assert_predicate(s.string, :ascii_only?)
end

def assert_string(content, encoding, str, mesg = nil)
Expand Down

0 comments on commit b31a538

Please sign in to comment.