FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Scan the code range when folding a compound string by jwils · Pull Request #9592 · jruby/jruby · GitHub

/ jruby Public

Scan the code range when folding a compound string - #9592

Merged
headius merged 1 commit into
jruby:jruby-10.0from
jwils:fix-folded-string-coderange
Aug 17, 2026
Merged

Scan the code range when folding a compound string#9592
headius merged 1 commit into
jruby:jruby-10.0from
jwils:fix-folded-string-coderange

Conversation

jwils commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Fixes #9591.

BuildCompoundStringInstr#simplifyInstr folds a compound string into a single
literal. Two places assigned CR_VALID without a scan of the bytes. A string
that holds only ASCII must be CR_7BIT.

String#hash mixes the encoding into the digest when a string is not 7-bit.
Two byte-identical strings with the same encoding therefore compared equal but
hashed differently, and Array#uniq, Hash and Set treated them as two
values.

The interpreter is not affected. interpret appends each piece with
RubyString#cat, which keeps the code range correct. The two modes disagreed,
so one process could hold both a correct and an incorrect copy of the same
text once the JIT threshold was crossed part way through a run.

The change

  • copy: keep the code range of the operand that is folded. The Frozen
    branch was already correct, because it reuses the operand and its code range.
  • the empty-string branch: use CR_7BIT. An empty string is 7-bit.

asOperand in the same file already uses CR_UNKNOWN, which is safe, because
a later scan computes the true value.

Which expressions were affected

Code range of the result, with -Xcompile.mode=FORCE:

Expression before after
"abc#{1}def" CR_VALID CR_7BIT
"abc#{:sym}def" CR_VALID CR_7BIT
"abc#{1.5}def" CR_VALID CR_7BIT
<<~ heredoc with an indented body CR_VALID CR_7BIT
"café#{1}!" CR_VALID CR_VALID

The dedent of a squiggly heredoc makes the parser produce a compound string,
which is why only the indented form was affected. An interpolated String was
not affected, because the parser merges those pieces earlier and rescans.

Tests

test/jruby/test_compound_string_coderange.rb is new. The bug only appears
once a method is compiled, so each case runs in a child process with
jruby.compile.mode=FORCE. Without this change 5 of the 6 tests fail. The
sixth checks that real non-ASCII text still gets CR_VALID, and it passes
either way.

I also ran spec/ruby/core/string, spec/ruby/core/symbol,
spec/ruby/core/encoding, spec/ruby/language/string_spec.rb and
spec/ruby/language/heredoc_spec.rb with -Xcompile.mode=FORCE. The result is
the same before and after: 4862 examples, 50 failures, 8 errors. Those failures
are already present on master.

headius left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

The fix makes sense. Normally I'd also prefer that the tests go into the RubySpec suite (spec/ruby), but I don't believe there's a good way to observe the code range from pure-Ruby.

We can go with this as-is and leave the test/jruby test in place.

headius commented Aug 17, 2026

Copy link
Copy Markdown
Member

I approved this PR, but it probably should be applied to JRuby 10.0 instead of master (10.1) as that is the current LTS and this is clearly an observable behavior difference from standard Ruby.

@jwils Could you rebase this fix atop the jruby-10.0 branch?

headius added this to the JRuby 10.0.7.0 milestone Aug 17, 2026
BuildCompoundStringInstr#simplifyInstr folds a compound string into a
single literal. It assigned CR_VALID without a scan of the bytes, so a
result that held only ASCII was marked as not 7-bit.

String#hash mixes the encoding into the digest when a string is not
7-bit. Two byte-identical strings then compared equal but hashed
differently, so uniq, Hash and Set split them.

The interpreter appends each piece with RubyString#cat and keeps the
code range correct, so this only appeared once a method was compiled.

Keep the code range of the operand that is folded, and use CR_7BIT for
the empty string.

Fixes jruby#9591
jwils force-pushed the fix-folded-string-coderange branch from abe4da2 to 522000a Compare August 17, 2026 20:34
jwils changed the base branch from master to jruby-10.0 August 17, 2026 20:34

jwils commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the quick review. Rebased.

headius left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Approved again. Might revisit the tests later to see if they make sense for rubyspec.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compiler gives a constant-folded ASCII String the code range CR_VALID, which breaks the eql? / hash contract

2 participants


Back | FazBrowse Home | New Git URL