Skip to content

Read sources as binary when checking for require_relative of extensions - #9968

Open
paracycle wants to merge 3 commits into
ruby:masterfrom
Shopify:sf/82564758-673a-469e-890f-55b92675f41b
Open

paracycle wants to merge 3 commits into
ruby:masterfrom
Shopify:sf/82564758-673a-469e-890f-55b92675f41b

Conversation

@paracycle

@paracycle paracycle commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What was the end-user or developer problem that led to this PR?

gem build aborts with ArgumentError: invalid byte sequence in US-ASCII for a gem with native extensions whose .rb files under its require paths contain non-ASCII characters, whenever the locale is unset or ASCII (build sandboxes such as Nix, minimal containers). We hit it building extlz4 0.3.5. Reported in #9966.

What is your fix for the problem, implemented in this PR?

Gem::SpecificationPolicy#validate_extension_require_relative (added in #9390) read each file with File.foreach(rb_file), which tags every line with Encoding.default_external. The require_relative regexp then raised on any line containing a non-ASCII byte, and the error escaped validation instead of producing a warning. A source that is not valid UTF-8 fails the same way under a UTF-8 locale.

The pattern is ASCII-only, so the file is now opened in binary mode (File.open(rb_file, "rb") with each_line). Passing encoding: to File.foreach would also work on CRuby, but JRuby raises TypeError: no implicit conversion of Hash into Integer for File.foreach with keyword arguments and no block. Two tests cover both cases: a non-ASCII UTF-8 source under a US-ASCII default external encoding, and a non-UTF-8 source under a UTF-8 one. Both raise without the fix, and the existing extension_require_relative tests still pass.

Fixes #9966

Make sure the following tasks are checked

Gem::SpecificationPolicy#validate_extension_require_relative read each file with File.foreach, which tags lines with Encoding.default_external. Under an unset or ASCII locale (build sandboxes, minimal containers) a valid UTF-8 non-ASCII line raised ArgumentError: invalid byte sequence in US-ASCII, and a non-UTF-8 source did the same under a UTF-8 locale. The error escaped validation and aborted gem build.

The pattern is ASCII-only, so read the file as binary.

Fixes ruby#9966
codespell read "caf" in the fixture as a misspelling of "calf". The test only needs bytes that are not valid UTF-8, so use \xFF\xFE.

Co-authored-by: Ufuk Kayserilioglu <ufuk.kayserilioglu@shopify.com>
@paracycle
paracycle marked this pull request as ready for review October 23, 2026 18:46
…reach

JRuby raises "TypeError: no implicit conversion of Hash into Integer" when File.foreach is called with keyword arguments and no block, as it is when chained with with_index. That broke every gem build in the JRuby Bundler specs. Opening the file with "rb" and iterating each_line reads the same binary lines on CRuby and JRuby.

Co-authored-by: Ufuk Kayserilioglu <ufuk.kayserilioglu@shopify.com>

File.foreach(rb_file).with_index(1) do |line, lineno|
next unless line =~ /^\s*require_relative\s+["']([^"']+)["']/
File.open(rb_file, "rb") do |file|

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

JRuby doesn't seem to handle options passed to File.foreach, so I had to change this to File.open followed with each_line.

/cc @headius

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for the ping, but where is the call passing options? I don't see it in this diff.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This branch has not been deployed

No deployments
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.

gem build fails under a non-UTF-8 locale for extension gems with non-ASCII source

2 participants