summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/zjit-macos.yml2
-rw-r--r--.github/workflows/zjit-ubuntu.yml2
-rw-r--r--NEWS.md5
-rw-r--r--ext/json/generator/generator.c17
-rw-r--r--ext/json/lib/json/version.rb2
-rw-r--r--ext/json/parser/parser.c44
-rw-r--r--lib/bundler/lockfile_parser.rb4
-rw-r--r--lib/bundler/templates/newgem/newgem.gemspec.tt2
-rw-r--r--lib/rubygems/request_set.rb65
-rw-r--r--lib/rubygems/request_set/lockfile.rb2
-rw-r--r--lib/rubygems/request_set/lockfile/parser.rb344
-rw-r--r--lib/rubygems/request_set/lockfile/tokenizer.rb122
-rw-r--r--lib/rubygems/yaml_serializer.rb60
-rw-r--r--marshal.c51
-rw-r--r--spec/bundler/bundler/lockfile_parser_spec.rb21
-rw-r--r--spec/bundler/quality_spec.rb2
-rw-r--r--test/json/json_parser_test.rb16
-rw-r--r--test/json/json_ryu_fallback_test.rb8
-rw-r--r--test/ruby/test_marshal.rb35
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock8
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock8
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_request_set.rb104
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_parser.rb544
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_tokenizer.rb307
-rw-r--r--test/rubygems/test_gem_safe_yaml.rb73
-rw-r--r--tool/bundler/dev_gems.rb2
-rw-r--r--tool/bundler/dev_gems.rb.lock6
-rw-r--r--tool/bundler/rubocop_gems.rb2
-rw-r--r--tool/bundler/rubocop_gems.rb.lock6
-rw-r--r--tool/bundler/standard_gems.rb2
-rw-r--r--tool/bundler/standard_gems.rb.lock6
-rw-r--r--tool/bundler/test_gems.rb2
-rw-r--r--tool/bundler/test_gems.rb.lock6
-rw-r--r--zjit/src/hir.rs1
-rw-r--r--zjit/src/hir/opt_tests.rs10
37 files changed, 466 insertions, 1429 deletions
diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml
index 3011a04cac..50c7bc190a 100644
--- a/.github/workflows/zjit-macos.yml
+++ b/.github/workflows/zjit-macos.yml
@@ -93,7 +93,7 @@ jobs:
rustup install ${{ matrix.rust_version }} --profile minimal
rustup default ${{ matrix.rust_version }}
- - uses: taiki-e/install-action@8f531eaecd1898bc3da7d104ad91bee98d1b97bd # v2.79.9
+ - uses: taiki-e/install-action@13608cbb45b01feb47ef444ab1a42dc41ad56f1a # v2.79.11
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml
index d91dfcbeeb..1e7bec3859 100644
--- a/.github/workflows/zjit-ubuntu.yml
+++ b/.github/workflows/zjit-ubuntu.yml
@@ -119,7 +119,7 @@ jobs:
ruby-version: '3.1'
bundler: none
- - uses: taiki-e/install-action@8f531eaecd1898bc3da7d104ad91bee98d1b97bd # v2.79.9
+ - uses: taiki-e/install-action@13608cbb45b01feb47ef444ab1a42dc41ad56f1a # v2.79.11
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
diff --git a/NEWS.md b/NEWS.md
index 9273e0adff..cfd90532b9 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -82,8 +82,8 @@ releases.
* 6.0.1 to [v6.0.1.1][erb-v6.0.1.1], [v6.0.2][erb-v6.0.2], [v6.0.3][erb-v6.0.3], [v6.0.4][erb-v6.0.4]
* ipaddr 1.2.9
* 1.2.8 to [v1.2.9][ipaddr-v1.2.9]
-* json 2.19.5
- * 2.18.0 to [v2.18.1][json-v2.18.1], [v2.19.0][json-v2.19.0], [v2.19.1][json-v2.19.1], [v2.19.2][json-v2.19.2], [v2.19.3][json-v2.19.3], [v2.19.4][json-v2.19.4], [v2.19.5][json-v2.19.5]
+* json 2.19.7
+ * 2.18.0 to [v2.18.1][json-v2.18.1], [v2.19.0][json-v2.19.0], [v2.19.1][json-v2.19.1], [v2.19.2][json-v2.19.2], [v2.19.3][json-v2.19.3], [v2.19.4][json-v2.19.4], [v2.19.5][json-v2.19.5], [v2.19.6][json-v2.19.6]
* openssl 4.0.2
* 4.0.0 to [v4.0.1][openssl-v4.0.1], [v4.0.2][openssl-v4.0.2]
* prism 1.9.0
@@ -208,6 +208,7 @@ A lot of work has gone into making Ractors more stable, performant, and usable.
[json-v2.19.3]: https://github.com/ruby/json/releases/tag/v2.19.3
[json-v2.19.4]: https://github.com/ruby/json/releases/tag/v2.19.4
[json-v2.19.5]: https://github.com/ruby/json/releases/tag/v2.19.5
+[json-v2.19.6]: https://github.com/ruby/json/releases/tag/v2.19.6
[openssl-v4.0.1]: https://github.com/ruby/openssl/releases/tag/v4.0.1
[openssl-v4.0.2]: https://github.com/ruby/openssl/releases/tag/v4.0.2
[prism-v1.8.0]: https://github.com/ruby/prism/releases/tag/v1.8.0
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c
index 882d47a611..9260712c9a 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -1367,12 +1367,14 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
MEMCPY(objState, origState, JSON_Generator_State, 1);
- objState->indent = origState->indent;
- objState->space = origState->space;
- objState->space_before = origState->space_before;
- objState->object_nl = origState->object_nl;
- objState->array_nl = origState->array_nl;
- objState->as_json = origState->as_json;
+
+ RB_OBJ_WRITTEN(obj, Qundef, objState->indent);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->space);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->space_before);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->object_nl);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->array_nl);
+ RB_OBJ_WRITTEN(obj, Qundef, objState->as_json);
+
return obj;
}
@@ -1590,6 +1592,9 @@ static long depth_config(VALUE num)
if (RB_UNLIKELY(d < 0)) {
rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d);
}
+ if (RB_UNLIKELY(d > INT_MAX)) {
+ rb_raise(rb_eArgError, "depth is too large (got %ld)", d);
+ }
return d;
}
diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb
index ebb55656d7..a69590ff9c 100644
--- a/ext/json/lib/json/version.rb
+++ b/ext/json/lib/json/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module JSON
- VERSION = '2.19.5'
+ VERSION = '2.19.7'
end
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c
index a740bd42ed..363f109d3a 100644
--- a/ext/json/parser/parser.c
+++ b/ext/json/parser/parser.c
@@ -1202,7 +1202,11 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
raise_parse_error_at("invalid number: %s", state, start);
}
- exponent = negative_exponent ? -abs_exponent : abs_exponent;
+ if (RB_UNLIKELY(exponent_digits >= 20 || abs_exponent > (uint64_t)INT64_MAX)) {
+ exponent = negative_exponent ? INT64_MIN : INT64_MAX;
+ } else {
+ exponent = negative_exponent ? -(int64_t)abs_exponent : (int64_t)abs_exponent;
+ }
}
if (integer) {
@@ -1457,18 +1461,21 @@ static void json_ensure_eof(JSON_ParserState *state)
static VALUE convert_encoding(VALUE source)
{
- int encindex = RB_ENCODING_GET(source);
+ StringValue(source);
+ int encindex = RB_ENCODING_GET(source);
- if (RB_LIKELY(encindex == utf8_encindex)) {
- return source;
- }
+ if (RB_LIKELY(encindex == utf8_encindex)) {
+ return source;
+ }
- if (encindex == binary_encindex) {
- // For historical reason, we silently reinterpret binary strings as UTF-8
- return rb_enc_associate_index(rb_str_dup(source), utf8_encindex);
- }
+ if (encindex == binary_encindex) {
+ // For historical reason, we silently reinterpret binary strings as UTF-8
+ return rb_enc_associate_index(rb_str_dup(source), utf8_encindex);
+ }
- return rb_funcall(source, i_encode, 1, Encoding_UTF_8);
+ source = rb_funcall(source, i_encode, 1, Encoding_UTF_8);
+ StringValue(source);
+ return source;
}
struct parser_config_init_args {
@@ -1583,10 +1590,16 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
return self;
}
-static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
+static VALUE cParser_parse(JSON_ParserConfig *config, VALUE src)
{
- Vsource = convert_encoding(StringValue(Vsource));
- StringValue(Vsource);
+ VALUE Vsource = convert_encoding(src);
+
+ // Ensure the string isn't mutated under us.
+ // The classic API to use is `rb_str_locktmp`, but then we'd
+ // need to use `rb_protect` to make sure we always unlock.
+ if (Vsource == src) {
+ Vsource = rb_str_new_frozen(Vsource);
+ }
VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
rvalue_stack stack = {
@@ -1597,6 +1610,7 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
long len;
const char *start;
+
RSTRING_GETMEM(Vsource, start, len);
VALUE stack_handle = 0;
@@ -1615,6 +1629,7 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
// it won't cause a leak.
rvalue_stack_eagerly_release(stack_handle);
RB_GC_GUARD(stack_handle);
+ RB_GC_GUARD(Vsource);
json_ensure_eof(state);
return result;
@@ -1635,9 +1650,6 @@ static VALUE cParserConfig_parse(VALUE self, VALUE Vsource)
static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
{
- Vsource = convert_encoding(StringValue(Vsource));
- StringValue(Vsource);
-
JSON_ParserConfig _config = {0};
JSON_ParserConfig *config = &_config;
parser_config_init(config, opts, false);
diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb
index 9e21f8f1d2..852fc631f3 100644
--- a/lib/bundler/lockfile_parser.rb
+++ b/lib/bundler/lockfile_parser.rb
@@ -95,14 +95,14 @@ module Bundler
lockfile_contents.split(BUNDLED).last.strip
end
- def initialize(lockfile, strict: false)
+ def initialize(lockfile, strict: false, lockfile_path: nil)
@platforms = []
@sources = []
@metadata_source = Source::Metadata.new
@dependencies = {}
@parse_method = nil
@specs = {}
- @lockfile_path = begin
+ @lockfile_path = lockfile_path || begin
SharedHelpers.relative_lockfile_path
rescue GemfileNotFound
"Gemfile.lock"
diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt
index 2729530e8d..1ab1c28f46 100644
--- a/lib/bundler/templates/newgem/newgem.gemspec.tt
+++ b/lib/bundler/templates/newgem/newgem.gemspec.tt
@@ -47,7 +47,7 @@ Gem::Specification.new do |spec|
# Uncomment to register a new dependency of your gem
# spec.add_dependency "example-gem", ">= 1.0"
<%- if config[:ext] == 'rust' -%>
- spec.add_dependency "rb_sys", ">= 0.9.127"
+ spec.add_dependency "rb_sys", ">= 0.9.128"
<%- end -%>
<%- if config[:ext] == 'go' -%>
spec.add_dependency "go_gem", ">= 0.2"
diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb
index dbebd1af0c..c06ef32da9 100644
--- a/lib/rubygems/request_set.rb
+++ b/lib/rubygems/request_set.rb
@@ -322,11 +322,8 @@ class Gem::RequestSet
@git_set.root_dir = @install_dir
lock_file = "#{File.expand_path(path)}.lock"
- begin
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file lock_file
- parser = tokenizer.make_parser self, []
- parser.parse
- rescue Errno::ENOENT
+ if File.exist?(lock_file)
+ load_lockfile lock_file
end
gf = Gem::RequestSet::GemDependencyAPI.new self, path
@@ -335,6 +332,63 @@ class Gem::RequestSet
gf.load
end
+ def load_lockfile(lock_file) # :nodoc:
+ require "bundler"
+ require "bundler/lockfile_parser"
+
+ # Bundler::Source::Path resolves relative `remote:` paths against
+ # Bundler.root, which raises when there is no Gemfile in the working
+ # directory. Anchor it to the lockfile's directory so PATH sections in a
+ # `gem install -g` lockfile can be parsed without a Bundler environment.
+ previous_root = Bundler.instance_variable_get(:@root)
+ Bundler.instance_variable_set(:@root, Pathname.new(File.expand_path(File.dirname(lock_file))))
+
+ parser = Bundler::LockfileParser.new(File.read(lock_file), lockfile_path: lock_file)
+
+ parser.specs.group_by(&:source).each do |source, specs|
+ case source
+ when Bundler::Source::Rubygems
+ remotes = source.remotes.map {|remote| Gem::Source.new(remote.to_s) }
+ remotes << Gem::Source.new(Gem::DEFAULT_HOST) if remotes.empty?
+ lock_set = Gem::Resolver::LockSet.new(remotes)
+ specs.each do |spec|
+ added = lock_set.add(spec.name, spec.version.to_s, spec.platform)
+ spec.dependencies.each do |dep|
+ added.each {|s| s.add_dependency dep }
+ end
+ end
+ @sets << lock_set
+ when Bundler::Source::Git
+ git_set = Gem::Resolver::GitSet.new
+ git_set.root_dir = @install_dir
+ specs.each do |spec|
+ git_spec = git_set.add_git_spec(
+ spec.name,
+ spec.version.to_s,
+ source.uri.to_s,
+ source.revision,
+ source.submodules || false
+ )
+ spec.dependencies.each {|dep| git_spec.add_dependency dep }
+ end
+ @sets << git_set
+ when Bundler::Source::Path
+ vendor_set = Gem::Resolver::VendorSet.new
+ specs.each do |spec|
+ loaded = vendor_set.add_vendor_gem(spec.name, source.path.to_s)
+ spec.dependencies.each {|dep| loaded.dependencies << dep }
+ end
+ @sets << vendor_set
+ end
+ end
+
+ parser.dependencies.each_value do |dep|
+ gem dep.name, *dep.requirement.as_list
+ end
+ ensure
+ Bundler.instance_variable_set(:@root, previous_root) if defined?(previous_root)
+ end
+
def pretty_print(q) # :nodoc:
q.group 2, "[RequestSet:", "]" do
q.breakable
@@ -462,4 +516,3 @@ end
require_relative "request_set/gem_dependency_api"
require_relative "request_set/lockfile"
-require_relative "request_set/lockfile/tokenizer"
diff --git a/lib/rubygems/request_set/lockfile.rb b/lib/rubygems/request_set/lockfile.rb
index da6dd329bc..8b9c9690d6 100644
--- a/lib/rubygems/request_set/lockfile.rb
+++ b/lib/rubygems/request_set/lockfile.rb
@@ -231,5 +231,3 @@ class Gem::RequestSet::Lockfile
@set.sorted_requests
end
end
-
-require_relative "lockfile/tokenizer"
diff --git a/lib/rubygems/request_set/lockfile/parser.rb b/lib/rubygems/request_set/lockfile/parser.rb
deleted file mode 100644
index e751a1445e..0000000000
--- a/lib/rubygems/request_set/lockfile/parser.rb
+++ /dev/null
@@ -1,344 +0,0 @@
-# frozen_string_literal: true
-
-class Gem::RequestSet::Lockfile::Parser
- ###
- # Parses lockfiles
-
- def initialize(tokenizer, set, platforms, filename = nil)
- @tokens = tokenizer
- @filename = filename
- @set = set
- @platforms = platforms
- end
-
- def parse
- until @tokens.empty? do
- token = get
-
- case token.type
- when :section then
- @tokens.skip :newline
-
- case token.value
- when "DEPENDENCIES" then
- parse_DEPENDENCIES
- when "GIT" then
- parse_GIT
- when "GEM" then
- parse_GEM
- when "PATH" then
- parse_PATH
- when "PLATFORMS" then
- parse_PLATFORMS
- else
- token = get until @tokens.empty? || peek.first == :section
- end
- else
- raise "BUG: unhandled token #{token.type} (#{token.value.inspect}) at line #{token.line} column #{token.column}"
- end
- end
- end
-
- ##
- # Gets the next token for a Lockfile
-
- def get(expected_types = nil, expected_value = nil) # :nodoc:
- token = @tokens.shift
-
- if expected_types && !Array(expected_types).include?(token.type)
- unget token
-
- message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " \
- "expected #{expected_types.inspect}"
-
- raise Gem::RequestSet::Lockfile::ParseError.new message, token.column, token.line, @filename
- end
-
- if expected_value && expected_value != token.value
- unget token
-
- message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " \
- "expected [#{expected_types.inspect}, " \
- "#{expected_value.inspect}]"
-
- raise Gem::RequestSet::Lockfile::ParseError.new message, token.column, token.line, @filename
- end
-
- token
- end
-
- def parse_DEPENDENCIES # :nodoc:
- while !@tokens.empty? && peek.type == :text do
- token = get :text
-
- requirements = []
-
- case peek[0]
- when :bang then
- get :bang
-
- requirements << pinned_requirement(token.value)
- when :l_paren then
- get :l_paren
-
- loop do
- op = get(:requirement).value
- version = get(:text).value
-
- requirements << "#{op} #{version}"
-
- break unless peek.type == :comma
-
- get :comma
- end
-
- get :r_paren
-
- if peek[0] == :bang
- requirements.clear
- requirements << pinned_requirement(token.value)
-
- get :bang
- end
- end
-
- @set.gem token.value, *requirements
-
- skip :newline
- end
- end
-
- def parse_GEM # :nodoc:
- sources = []
-
- while peek.first(2) == [:entry, "remote"] do
- get :entry, "remote"
- data = get(:text).value
- skip :newline
-
- sources << Gem::Source.new(data)
- end
-
- sources << Gem::Source.new(Gem::DEFAULT_HOST) if sources.empty?
-
- get :entry, "specs"
-
- skip :newline
-
- set = Gem::Resolver::LockSet.new sources
- last_specs = nil
-
- while !@tokens.empty? && peek.type == :text do
- token = get :text
- name = token.value
- column = token.column
-
- case peek[0]
- when :newline then
- last_specs.each do |spec|
- spec.add_dependency Gem::Dependency.new name if column == 6
- end
- when :l_paren then
- get :l_paren
-
- token = get [:text, :requirement]
- type = token.type
- data = token.value
-
- if type == :text && column == 4
- version, platform = data.split "-", 2
-
- platform =
- platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
-
- last_specs = set.add name, version, platform
- else
- dependency = parse_dependency name, data
-
- last_specs.each do |spec|
- spec.add_dependency dependency
- end
- end
-
- get :r_paren
- else
- raise "BUG: unknown token #{peek}"
- end
-
- skip :newline
- end
-
- @set.sets << set
- end
-
- def parse_GIT # :nodoc:
- get :entry, "remote"
- repository = get(:text).value
-
- skip :newline
-
- get :entry, "revision"
- revision = get(:text).value
-
- skip :newline
-
- type = peek.type
- value = peek.value
- if type == :entry && %w[branch ref tag].include?(value)
- get
- get :text
-
- skip :newline
- end
-
- get :entry, "specs"
-
- skip :newline
-
- set = Gem::Resolver::GitSet.new
- set.root_dir = @set.install_dir
-
- last_spec = nil
-
- while !@tokens.empty? && peek.type == :text do
- token = get :text
- name = token.value
- column = token.column
-
- case peek[0]
- when :newline then
- last_spec.add_dependency Gem::Dependency.new name if column == 6
- when :l_paren then
- get :l_paren
-
- token = get [:text, :requirement]
- type = token.type
- data = token.value
-
- if type == :text && column == 4
- last_spec = set.add_git_spec name, data, repository, revision, true
- else
- dependency = parse_dependency name, data
-
- last_spec.add_dependency dependency
- end
-
- get :r_paren
- else
- raise "BUG: unknown token #{peek}"
- end
-
- skip :newline
- end
-
- @set.sets << set
- end
-
- def parse_PATH # :nodoc:
- get :entry, "remote"
- directory = get(:text).value
-
- skip :newline
-
- get :entry, "specs"
-
- skip :newline
-
- set = Gem::Resolver::VendorSet.new
- last_spec = nil
-
- while !@tokens.empty? && peek.first == :text do
- token = get :text
- name = token.value
- column = token.column
-
- case peek[0]
- when :newline then
- last_spec.add_dependency Gem::Dependency.new name if column == 6
- when :l_paren then
- get :l_paren
-
- token = get [:text, :requirement]
- type = token.type
- data = token.value
-
- if type == :text && column == 4
- last_spec = set.add_vendor_gem name, directory
- else
- dependency = parse_dependency name, data
-
- last_spec.dependencies << dependency
- end
-
- get :r_paren
- else
- raise "BUG: unknown token #{peek}"
- end
-
- skip :newline
- end
-
- @set.sets << set
- end
-
- def parse_PLATFORMS # :nodoc:
- while !@tokens.empty? && peek.first == :text do
- name = get(:text).value
-
- @platforms << name
-
- skip :newline
- end
- end
-
- ##
- # Parses the requirements following the dependency +name+ and the +op+ for
- # the first token of the requirements and returns a Gem::Dependency object.
-
- def parse_dependency(name, op) # :nodoc:
- return Gem::Dependency.new name, op unless peek[0] == :text
-
- version = get(:text).value
-
- requirements = ["#{op} #{version}"]
-
- while peek.type == :comma do
- get :comma
- op = get(:requirement).value
- version = get(:text).value
-
- requirements << "#{op} #{version}"
- end
-
- Gem::Dependency.new name, requirements
- end
-
- private
-
- def skip(type) # :nodoc:
- @tokens.skip type
- end
-
- ##
- # Peeks at the next token for Lockfile
-
- def peek # :nodoc:
- @tokens.peek
- end
-
- def pinned_requirement(name) # :nodoc:
- requirement = Gem::Dependency.new name
- specification = @set.sets.flat_map do |set|
- set.find_all(requirement)
- end.compact.first
-
- specification&.version
- end
-
- ##
- # Ungets the last token retrieved by #get
-
- def unget(token) # :nodoc:
- @tokens.unshift token
- end
-end
diff --git a/lib/rubygems/request_set/lockfile/tokenizer.rb b/lib/rubygems/request_set/lockfile/tokenizer.rb
deleted file mode 100644
index 65cef3baa0..0000000000
--- a/lib/rubygems/request_set/lockfile/tokenizer.rb
+++ /dev/null
@@ -1,122 +0,0 @@
-# frozen_string_literal: true
-
-# ) frozen_string_literal: true
-require_relative "parser"
-
-class Gem::RequestSet::Lockfile::Tokenizer
- Token = Struct.new :type, :value, :column, :line
- EOF = Token.new :EOF
-
- def self.from_file(file)
- new File.read(file), file
- end
-
- def initialize(input, filename = nil, line = 0, pos = 0)
- @line = line
- @line_pos = pos
- @tokens = []
- @filename = filename
- tokenize input
- end
-
- def make_parser(set, platforms)
- Gem::RequestSet::Lockfile::Parser.new self, set, platforms, @filename
- end
-
- def to_a
- @tokens.map {|token| [token.type, token.value, token.column, token.line] }
- end
-
- def skip(type)
- @tokens.shift while !@tokens.empty? && peek.type == type
- end
-
- ##
- # Calculates the column (by byte) and the line of the current token based on
- # +byte_offset+.
-
- def token_pos(byte_offset) # :nodoc:
- [byte_offset - @line_pos, @line]
- end
-
- def empty?
- @tokens.empty?
- end
-
- def unshift(token)
- @tokens.unshift token
- end
-
- def next_token
- @tokens.shift
- end
- alias_method :shift, :next_token
-
- def peek
- @tokens.first || EOF
- end
-
- private
-
- def tokenize(input)
- require "strscan"
- s = StringScanner.new input
-
- until s.eos? do
- pos = s.pos
-
- pos = s.pos if leading_whitespace = s.scan(/ +/)
-
- if s.scan(/[<|=>]{7}/)
- message = "your #{@filename} contains merge conflict markers"
- column, line = token_pos pos
-
- raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename
- end
-
- @tokens <<
- if s.scan(/\r?\n/)
-
- token = Token.new(:newline, nil, *token_pos(pos))
- @line_pos = s.pos
- @line += 1
- token
- elsif s.scan(/[A-Z]+/)
-
- if leading_whitespace
- text = s.matched
- text += s.scan(/[^\s)]*/).to_s # in case of no match
- Token.new(:text, text, *token_pos(pos))
- else
- Token.new(:section, s.matched, *token_pos(pos))
- end
- elsif s.scan(/([a-z]+):\s/)
-
- s.pos -= 1 # rewind for possible newline
- Token.new(:entry, s[1], *token_pos(pos))
- elsif s.scan(/\(/)
-
- Token.new(:l_paren, nil, *token_pos(pos))
- elsif s.scan(/\)/)
-
- Token.new(:r_paren, nil, *token_pos(pos))
- elsif s.scan(/<=|>=|=|~>|<|>|!=/)
-
- Token.new(:requirement, s.matched, *token_pos(pos))
- elsif s.scan(/,/)
-
- Token.new(:comma, nil, *token_pos(pos))
- elsif s.scan(/!/)
-
- Token.new(:bang, nil, *token_pos(pos))
- elsif s.scan(/[^\s),!]*/)
-
- Token.new(:text, s.matched, *token_pos(pos))
- else
- raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}"
- end
- end
-
- @tokens
- end
-end
diff --git a/lib/rubygems/yaml_serializer.rb b/lib/rubygems/yaml_serializer.rb
index a1d5c94fc5..b2547b136b 100644
--- a/lib/rubygems/yaml_serializer.rb
+++ b/lib/rubygems/yaml_serializer.rb
@@ -72,9 +72,7 @@ module Gem
def parse_node(base_indent)
@depth += 1
- if @depth > MAX_NESTING_DEPTH
- raise Psych::SyntaxError, "exceeded maximum nesting depth (#{MAX_NESTING_DEPTH})"
- end
+ raise_max_nesting! if @depth > MAX_NESTING_DEPTH
skip_blank_and_comments
return nil if @lines.empty?
@@ -285,7 +283,9 @@ module Gem
Scalar.new(value: result)
end
- def coerce(val)
+ def coerce(val, depth = 0)
+ raise_max_nesting! if depth > MAX_NESTING_DEPTH
+
val = val.sub(/^! /, "") if val.start_with?("! ")
if val =~ /^"(.*)"$/
@@ -311,7 +311,7 @@ module Gem
elsif val =~ /^\[(.*)\]$/
inner = $1.strip
return Sequence.new if inner.empty?
- items = inner.split(/\s*,\s*/).reject(&:empty?).map {|e| Scalar.new(value: coerce(e)) }
+ items = inner.split(/\s*,\s*/).reject(&:empty?).map {|e| Scalar.new(value: coerce(e, depth + 1)) }
Sequence.new(items: items)
elsif /\A\d{4}-\d{2}-\d{2}([ T]\d{2}:\d{2}:\d{2})?/.match?(val)
begin
@@ -392,6 +392,15 @@ module Gem
node
end
+ def raise_max_nesting!
+ message = "exceeded maximum nesting depth (#{MAX_NESTING_DEPTH})"
+ if defined?(Psych::VERSION)
+ raise Psych::SyntaxError.new(nil, 0, 0, 0, message, nil)
+ else
+ raise Psych::SyntaxError, message
+ end
+ end
+
def skip_blank_and_comments
while @lines.any?
line = @lines[0]
@@ -454,9 +463,7 @@ module Gem
result = build_node(node)
- if result.is_a?(Hash) &&
- (result[:tag] == "!ruby/object:Gem::Specification" ||
- result["tag"] == "!ruby/object:Gem::Specification")
+ if result.is_a?(Hash) && result[:tag] == "!ruby/object:Gem::Specification"
build_specification(result)
else
result
@@ -482,7 +489,11 @@ module Gem
if @alias_count > MAX_ALIAS_RESOLUTIONS
raise Psych::BadAlias, "exceeded maximum alias resolutions (#{MAX_ALIAS_RESOLUTIONS})"
end
- @anchor_values.fetch(node.name, nil)
+ unless @anchor_values.key?(node.name)
+ klass = defined?(Psych::AnchorNotDefined) ? Psych::AnchorNotDefined : Psych::BadAlias
+ raise klass, "An alias referenced an unknown anchor: #{node.name}"
+ end
+ @anchor_values.fetch(node.name)
end
def store_anchor(name, value)
@@ -491,7 +502,6 @@ module Gem
end
def build_mapping(node)
- check_anchor!(node)
validate_tag!(node.tag) if node.tag
result = case node.tag
@@ -592,9 +602,14 @@ module Gem
d.instance_variable_set(:@requirement, hash["requirement"] || hash["version_requirements"])
- type = hash["type"]
- type = type ? type.to_s.sub(/^:/, "").to_sym : :runtime
- validate_symbol!(type)
+ raw_type = hash["type"]
+ if raw_type
+ name = raw_type.to_s.sub(/^:/, "")
+ validate_symbol!(name)
+ type = name.to_sym
+ else
+ type = :runtime
+ end
d.instance_variable_set(:@type, type)
d.instance_variable_set(:@prerelease, ["true", true].include?(hash["prerelease"]))
@@ -634,19 +649,14 @@ module Gem
end
end
- def validate_symbol!(sym)
- if @permitted_symbols.any? && !@permitted_symbols.include?(sym.to_s)
- if defined?(Psych::VERSION)
- raise Psych::DisallowedClass.new("load", sym.inspect)
- else
- raise Psych::DisallowedClass, "Tried to load unspecified class: #{sym.inspect}"
- end
- end
- end
+ def validate_symbol!(name)
+ return if @permitted_symbols.empty? || @permitted_symbols.include?(name)
- def check_anchor!(node)
- if node.anchor
- raise Psych::AliasesNotEnabled unless @aliases
+ label = ":#{name}"
+ if defined?(Psych::VERSION)
+ raise Psych::DisallowedClass.new("load", label)
+ else
+ raise Psych::DisallowedClass, "Tried to load unspecified class: #{label}"
end
end
diff --git a/marshal.c b/marshal.c
index 18cacd410f..e6ee3b47b0 100644
--- a/marshal.c
+++ b/marshal.c
@@ -1242,6 +1242,7 @@ rb_marshal_dump_limited(VALUE obj, VALUE port, int limit)
struct load_arg {
VALUE src;
char *buf;
+ long bufsize;
long buflen;
long readable;
long offset;
@@ -1327,15 +1328,23 @@ static unsigned char
r_byte1_buffered(struct load_arg *arg)
{
if (arg->buflen == 0) {
- long readable = arg->readable < BUFSIZ ? arg->readable : BUFSIZ;
+ long readable = arg->readable < arg->bufsize ? arg->readable : arg->bufsize;
+ long read_len;
VALUE str, n = LONG2NUM(readable);
str = load_funcall(arg, arg->src, s_read, 1, &n);
if (NIL_P(str)) too_short();
StringValue(str);
- memcpy(arg->buf, RSTRING_PTR(str), RSTRING_LEN(str));
+ read_len = RSTRING_LEN(str);
+ if (UNLIKELY(read_len < readable)) too_short();
+ if (UNLIKELY(read_len > arg->bufsize)) {
+ arg->buf = ruby_sized_realloc_n(arg->buf, read_len, 1, arg->bufsize);
+ arg->bufsize = read_len;
+ }
+ memcpy(arg->buf, RSTRING_PTR(str), read_len);
arg->offset = 0;
- arg->buflen = RSTRING_LEN(str);
+ arg->buflen = read_len;
+ RB_GC_GUARD(str);
}
arg->buflen--;
return arg->buf[arg->offset++];
@@ -1422,6 +1431,18 @@ ruby_marshal_read_long(const char **buf, long len)
return x;
}
+static long
+r_keep_readable(struct load_arg *arg, long len, size_t size)
+{
+ if (UNLIKELY(len < 0)) {
+ rb_raise(rb_eArgError, "negative length");
+ }
+ if (UNLIKELY((unsigned long)len > SIZE_MAX / size || arg->readable >= LONG_MAX - len)) {
+ rb_raise(rb_eArgError, "marshaled data too big");
+ }
+ return len;
+}
+
static VALUE
r_bytes1(long len, struct load_arg *arg)
{
@@ -1451,7 +1472,7 @@ r_bytes1_buffered(long len, struct load_arg *arg)
long tmp_len, read_len, need_len = len - buflen;
VALUE tmp, n;
- readable = readable < BUFSIZ ? readable : BUFSIZ;
+ readable = readable < arg->bufsize ? readable : arg->bufsize;
read_len = need_len > readable ? need_len : readable;
n = LONG2NUM(read_len);
tmp = load_funcall(arg, arg->src, s_read, 1, &n);
@@ -2005,7 +2026,10 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE ex
int sign;
sign = r_byte(arg);
- len = r_long(arg);
+ if (sign != '+' && sign != '-') {
+ rb_raise(rb_eArgError, "invalid Bignum sign");
+ }
+ len = r_keep_readable(arg, r_long(arg), 2);
if (SIZEOF_VALUE >= 8 && len <= 4) {
// Representable within uintptr, likely FIXNUM
@@ -2083,7 +2107,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE ex
case TYPE_ARRAY:
{
- long len = r_long(arg);
+ long len = r_keep_readable(arg, r_long(arg), 1);
v = rb_ary_new2(len);
v = r_entry(v, arg);
@@ -2101,7 +2125,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE ex
case TYPE_HASH_DEF:
type_hash:
{
- long len = r_long(arg);
+ long len = r_keep_readable(arg, r_long(arg), 2);
v = hash_new_with_size(len);
v = r_entry(v, arg);
@@ -2127,7 +2151,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE klass, VALUE ex
VALUE slot;
st_index_t idx = r_prepare(arg);
VALUE klass = path2class(r_unique(arg));
- long len = r_long(arg);
+ long len = r_keep_readable(arg, r_long(arg), 2);
v = rb_obj_alloc(klass);
if (!RB_TYPE_P(v, T_STRUCT)) {
@@ -2344,8 +2368,9 @@ r_object(struct load_arg *arg)
static void
clear_load_arg(struct load_arg *arg)
{
- ruby_xfree_sized(arg->buf, BUFSIZ);
+ ruby_xfree_sized(arg->buf, arg->bufsize);
arg->buf = NULL;
+ arg->bufsize = 0;
arg->buflen = 0;
arg->offset = 0;
arg->readable = 0;
@@ -2391,10 +2416,14 @@ rb_marshal_load_with_proc(VALUE port, VALUE proc, bool freeze)
arg->readable = 0;
arg->freeze = freeze;
- if (NIL_P(v))
+ if (NIL_P(v)) {
+ arg->bufsize = BUFSIZ;
arg->buf = xmalloc(BUFSIZ);
- else
+ }
+ else {
+ arg->bufsize = 0;
arg->buf = 0;
+ }
major = r_byte(arg);
minor = r_byte(arg);
diff --git a/spec/bundler/bundler/lockfile_parser_spec.rb b/spec/bundler/bundler/lockfile_parser_spec.rb
index 4b493a3757..7364ab98e5 100644
--- a/spec/bundler/bundler/lockfile_parser_spec.rb
+++ b/spec/bundler/bundler/lockfile_parser_spec.rb
@@ -252,6 +252,27 @@ RSpec.describe Bundler::LockfileParser do
end
end
+ context "when lockfile_path is given" do
+ it "uses the provided path in error messages instead of looking up Bundler.default_lockfile" do
+ expect(Bundler::SharedHelpers).not_to receive(:relative_lockfile_path)
+ parser = described_class.new(lockfile_contents, lockfile_path: "custom/path.lock")
+ expect(parser.valid?).to be(true)
+ rake_spec = parser.specs.last
+ checksums = parser.sources.last.checksum_store.to_lock(rake_spec)
+ expected_checksum = Bundler::Checksum.from_lock(
+ "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
+ "custom/path.lock:20:17"
+ )
+ expect(checksums).to eq("#{rake_spec.lock_name} #{expected_checksum.to_lock}")
+ end
+
+ it "raises with the provided path when the lockfile contains merge conflicts" do
+ expect do
+ described_class.new("<<<<<<<\n", lockfile_path: "custom/path.lock")
+ end.to raise_error(Bundler::LockfileError, %r{custom/path\.lock contains merge conflicts})
+ end
+ end
+
context "when CHECKSUMS has duplicate checksums in the lockfile that don't match" do
let(:bad_checksum) { "sha256=c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11" }
let(:lockfile_contents) { super().split(/(?<=CHECKSUMS\n)/m).insert(1, " rake (10.3.2) #{bad_checksum}\n").join }
diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb
index 33ae503a5a..16b7f18788 100644
--- a/spec/bundler/quality_spec.rb
+++ b/spec/bundler/quality_spec.rb
@@ -109,7 +109,7 @@ RSpec.describe "The library itself" do
it "does not include any unresolved merge conflicts" do
error_messages = []
- exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser\.rb}
+ exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser}
tracked_files.each do |filename|
next if filename&.match?(exempt)
error_messages << check_for_git_merge_conflicts(filename)
diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb
index 67d86a0b35..1969e79b31 100644
--- a/test/json/json_parser_test.rb
+++ b/test/json/json_parser_test.rb
@@ -878,6 +878,22 @@ class JSONParserTest < Test::Unit::TestCase
end
end
+ def test_mutating_source_string_during_parsing
+ expected = ([1] * 100) + [2.3] + ([1] * 100)
+ source = JSON.generate(expected)
+ expected.delete_at(100)
+
+ fake_decimal_class = Class.new
+ fake_decimal_class.define_method(:initialize) do |number|
+ source.tr!('1', '0')
+ number.to_f
+ end
+
+ actual = JSON.parse(source, decimal_class: fake_decimal_class)
+ actual.delete_at(100)
+ assert_equal expected, actual
+ end
+
private
def assert_equal_float(expected, actual, delta = 1e-2)
diff --git a/test/json/json_ryu_fallback_test.rb b/test/json/json_ryu_fallback_test.rb
index 152de7e360..a61b3e668d 100644
--- a/test/json/json_ryu_fallback_test.rb
+++ b/test/json/json_ryu_fallback_test.rb
@@ -179,5 +179,13 @@ class JSONRyuFallbackTest < Test::Unit::TestCase
assert_equal(-0.0, JSON.parse("-99999999999999999e-4294967296"))
assert_equal(-Float::INFINITY, JSON.parse("-1e4294967295"))
assert_equal(-Float::INFINITY, JSON.parse("-1e4294967297"))
+
+ assert_equal(Float::INFINITY, JSON.parse("1e9223372036854775808"))
+ assert_equal(Float::INFINITY, JSON.parse("1e9999999999999999999"))
+ assert_equal(Float::INFINITY, JSON.parse("1e18446744073709551616"))
+ assert_equal(Float::INFINITY, JSON.parse("1e10000000000000000000"))
+ assert_equal(Float::INFINITY, JSON.parse("1e184467440737095516160"))
+ assert_equal 0.0, JSON.parse("1e-18446744073709551615")
+ assert_equal 0.0, JSON.parse("1e-9223372036854775809")
end
end
diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb
index 1e4de74503..48a67e1dc5 100644
--- a/test/ruby/test_marshal.rb
+++ b/test/ruby/test_marshal.rb
@@ -933,6 +933,41 @@ class TestMarshal < Test::Unit::TestCase
end
end
+ def test_load_overread
+ input = Struct.new(:bytes, :used) do
+ def initialize
+ super("\x04\x08[\x07".bytes, false)
+ end
+
+ def getbyte
+ bytes.shift
+ end
+
+ def read(_len, _outbuf = nil)
+ return nil if used
+ self.used = true
+ "0" * (1024 * 128)
+ end
+ end.new
+
+ assert_equal([nil, nil], Marshal.load(input))
+ end
+
+ def test_bignum_len_overflow
+ assert_raise(ArgumentError) do
+ Marshal.load("\x04\x08l+\x04\x00\x00\x00\x40")
+ end
+ assert_raise(ArgumentError) do
+ Marshal.load("\x04\x08l+\xfc\x00\x00\x00\x80")
+ end
+ end
+
+ def test_bignum_invalid_sign
+ assert_raise(ArgumentError) do
+ Marshal.load("\x04\bl?")
+ end
+ end
+
class TestMarshalFreezeProc < Test::Unit::TestCase
include MarshalTestLib
diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock
index 989b0b0412..d6c49c3de1 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock
+++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock
@@ -153,18 +153,18 @@ dependencies = [
[[package]]
name = "rb-sys"
-version = "0.9.127"
+version = "0.9.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7d7c9560fe42dcffa576941394075f18a17dce89fcf718a2fa90b7dc2134d12"
+checksum = "45ca28513560e56cfb79a62b1fce363c73af170a182024ce880c77ee9429920a"
dependencies = [
"rb-sys-build",
]
[[package]]
name = "rb-sys-build"
-version = "0.9.127"
+version = "0.9.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1688e8f32967ba48c89e4dfa283b57f901075f542fc7ee9c3d7c5f9091ca1d9"
+checksum = "ce04b2c55eff3a21aaa623fcc655d94373238e72cac6b3e1a3641ff31649f99a"
dependencies = [
"bindgen",
"lazy_static",
diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml
index 47e978ceb4..056567c708 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml
+++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2021"
crate-type = ["cdylib"]
[dependencies]
-rb-sys = "0.9.127"
+rb-sys = "0.9.128"
diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
index e8ee8f237c..806d51d3a1 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
+++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
@@ -146,18 +146,18 @@ dependencies = [
[[package]]
name = "rb-sys"
-version = "0.9.127"
+version = "0.9.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7d7c9560fe42dcffa576941394075f18a17dce89fcf718a2fa90b7dc2134d12"
+checksum = "45ca28513560e56cfb79a62b1fce363c73af170a182024ce880c77ee9429920a"
dependencies = [
"rb-sys-build",
]
[[package]]
name = "rb-sys-build"
-version = "0.9.127"
+version = "0.9.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1688e8f32967ba48c89e4dfa283b57f901075f542fc7ee9c3d7c5f9091ca1d9"
+checksum = "ce04b2c55eff3a21aaa623fcc655d94373238e72cac6b3e1a3641ff31649f99a"
dependencies = [
"bindgen",
"lazy_static",
diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
index 6595b6aafa..f0ddeeb91c 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
+++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2021"
crate-type = ["cdylib"]
[dependencies]
-rb-sys = "0.9.127"
+rb-sys = "0.9.128"
diff --git a/test/rubygems/test_gem_request_set.rb b/test/rubygems/test_gem_request_set.rb
index 9aa244892c..6ebc95ea20 100644
--- a/test/rubygems/test_gem_request_set.rb
+++ b/test/rubygems/test_gem_request_set.rb
@@ -311,6 +311,110 @@ ruby "0"
assert_empty rs.dependencies
end
+ def test_load_gemdeps_with_lockfile_gem_section
+ rs = Gem::RequestSet.new
+
+ File.open "gem.deps.rb", "w" do |io|
+ io.puts 'gem "b"'
+ end
+
+ File.open "gem.deps.rb.lock", "w" do |io|
+ io.puts <<~LOCKFILE
+ GEM
+ remote: #{@gem_repo}
+ specs:
+ a (1)
+ b (1)
+ a (~> 1.0)
+
+ PLATFORMS
+ #{Gem::Platform::RUBY}
+
+ DEPENDENCIES
+ b
+ LOCKFILE
+ end
+
+ rs.load_gemdeps "gem.deps.rb"
+
+ lock_set = rs.sets.find {|set| Gem::Resolver::LockSet === set }
+ refute_nil lock_set, "LockSet should be created from GEM section"
+ assert_equal %w[a-1 b-1], lock_set.specs.map(&:full_name).sort
+ end
+
+ def test_load_gemdeps_with_lockfile_git_section
+ rs = Gem::RequestSet.new
+
+ File.open "gem.deps.rb", "w" do |io|
+ io.puts 'gem "a", :git => "git://example/a.git"'
+ end
+
+ File.open "gem.deps.rb.lock", "w" do |io|
+ io.puts <<~LOCKFILE
+ GIT
+ remote: git://example/a.git
+ revision: deadbeef
+ specs:
+ a (1)
+
+ PLATFORMS
+ #{Gem::Platform::RUBY}
+
+ DEPENDENCIES
+ a!
+ LOCKFILE
+ end
+
+ rs.load_gemdeps "gem.deps.rb"
+
+ git_set = rs.sets.find {|set| Gem::Resolver::GitSet === set }
+ refute_nil git_set, "GitSet should be created from GIT section"
+ assert_includes git_set.specs.keys, "a"
+ end
+
+ def test_load_gemdeps_with_lockfile_path_section
+ _, _, directory = vendor_gem
+
+ rs = Gem::RequestSet.new
+
+ File.open "gem.deps.rb", "w" do |io|
+ io.puts "gem \"a\", :path => #{directory.inspect}"
+ end
+
+ File.open "gem.deps.rb.lock", "w" do |io|
+ io.puts <<~LOCKFILE
+ PATH
+ remote: #{directory}
+ specs:
+ a (1)
+
+ PLATFORMS
+ #{Gem::Platform::RUBY}
+
+ DEPENDENCIES
+ a!
+ LOCKFILE
+ end
+
+ rs.load_gemdeps "gem.deps.rb"
+
+ vendor_set = rs.sets.find {|set| Gem::Resolver::VendorSet === set }
+ refute_nil vendor_set, "VendorSet should be created from PATH section"
+ assert_equal %w[a-1], vendor_set.specs.values.map(&:full_name)
+ end
+
+ def test_load_gemdeps_with_missing_lockfile
+ rs = Gem::RequestSet.new
+
+ File.open "gem.deps.rb", "w" do |io|
+ io.puts 'gem "a"'
+ end
+
+ rs.load_gemdeps "gem.deps.rb"
+
+ assert_equal [dep("a")], rs.dependencies
+ end
+
def test_resolve
a = util_spec "a", "2", "b" => ">= 2"
b = util_spec "b", "2"
diff --git a/test/rubygems/test_gem_request_set_lockfile_parser.rb b/test/rubygems/test_gem_request_set_lockfile_parser.rb
deleted file mode 100644
index 253a59b243..0000000000
--- a/test/rubygems/test_gem_request_set_lockfile_parser.rb
+++ /dev/null
@@ -1,544 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helper"
-require "rubygems/request_set"
-require "rubygems/request_set/lockfile"
-require "rubygems/request_set/lockfile/tokenizer"
-require "rubygems/request_set/lockfile/parser"
-
-class TestGemRequestSetLockfileParser < Gem::TestCase
- def setup
- super
- @gem_deps_file = "gem.deps.rb"
- @lock_file = File.expand_path "#{@gem_deps_file}.lock"
- @set = Gem::RequestSet.new
- end
-
- def test_get
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n"
- parser = tokenizer.make_parser nil, nil
-
- assert_equal :newline, parser.get.first
- end
-
- def test_get_type_mismatch
- filename = File.expand_path("#{@gem_deps_file}.lock")
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "foo", filename, 1, 0
- parser = tokenizer.make_parser nil, nil
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- parser.get :section
- end
-
- expected =
- 'unexpected token [:text, "foo"], expected :section (at line 1 column 0)'
-
- assert_equal expected, e.message
-
- assert_equal 1, e.line
- assert_equal 0, e.column
- assert_equal filename, e.path
- end
-
- def test_get_type_multiple
- filename = File.expand_path("#{@gem_deps_file}.lock")
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "x", filename, 1
- parser = tokenizer.make_parser nil, nil
-
- assert parser.get [:text, :section]
- end
-
- def test_get_type_value_mismatch
- filename = File.expand_path("#{@gem_deps_file}.lock")
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "x", filename, 1
- parser = tokenizer.make_parser nil, nil
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- parser.get :text, "y"
- end
-
- expected =
- 'unexpected token [:text, "x"], expected [:text, "y"] (at line 1 column 0)'
-
- assert_equal expected, e.message
-
- assert_equal 1, e.line
- assert_equal 0, e.column
- assert_equal File.expand_path("#{@gem_deps_file}.lock"), e.path
- end
-
- def test_parse
- write_lockfile <<-LOCKFILE.strip
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- a
- LOCKFILE
-
- platforms = []
- parse_lockfile @set, platforms
-
- assert_equal [dep("a")], @set.dependencies
-
- assert_equal [Gem::Platform::RUBY], platforms
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "could not find a LockSet"
-
- assert_equal %w[a-2], lockfile_set.specs.map(&:full_name)
- end
-
- def test_parse_dependencies
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- a (>= 1, <= 2)
- LOCKFILE
-
- platforms = []
- parse_lockfile @set, platforms
-
- assert_equal [dep("a", ">= 1", "<= 2")], @set.dependencies
-
- assert_equal [Gem::Platform::RUBY], platforms
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "could not find a LockSet"
-
- assert_equal %w[a-2], lockfile_set.specs.map(&:full_name)
- end
-
- def test_parse_DEPENDENCIES_git
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://git.example/josevalim/rails-footnotes.git
- revision: 3a6ac1971e91d822f057650cc5916ebfcbd6ee37
- specs:
- rails-footnotes (3.7.9)
- rails (>= 3.0.0)
-
-GIT
- remote: git://git.example/svenfuchs/i18n-active_record.git
- revision: 55507cf59f8f2173d38e07e18df0e90d25b1f0f6
- specs:
- i18n-active_record (0.0.2)
- i18n (>= 0.5.0)
-
-GEM
- remote: http://gems.example/
- specs:
- i18n (0.6.9)
- rails (4.0.0)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- i18n-active_record!
- rails-footnotes!
- LOCKFILE
-
- parse_lockfile @set, []
-
- expected = [
- dep("i18n-active_record", "= 0.0.2"),
- dep("rails-footnotes", "= 3.7.9"),
- ]
-
- assert_equal expected, @set.dependencies
- end
-
- def test_parse_DEPENDENCIES_git_version
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://github.com/progrium/ruby-jwt.git
- revision: 8d74770c6cd92ea234b428b5d0c1f18306a4f41c
- specs:
- jwt (1.1)
-
-GEM
- remote: http://gems.example/
- specs:
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- jwt (= 1.1)!
- LOCKFILE
-
- parse_lockfile @set, []
-
- expected = [
- dep("jwt", "= 1.1"),
- ]
-
- assert_equal expected, @set.dependencies
- end
-
- def test_parse_GEM
- write_lockfile <<-LOCKFILE
-GEM
- specs:
- a (2)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- a
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", ">= 0")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "found a LockSet"
-
- assert_equal %w[a-2], lockfile_set.specs.map(&:full_name)
- end
-
- def test_parse_GEM_remote_multiple
- write_lockfile <<-LOCKFILE
-GEM
- remote: https://gems.example/
- remote: https://other.example/
- specs:
- a (2)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- a
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", ">= 0")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "found a LockSet"
-
- assert_equal %w[a-2], lockfile_set.specs.map(&:full_name)
-
- assert_equal %w[https://gems.example/ https://other.example/],
- lockfile_set.specs.flat_map {|s| s.sources.map {|src| src.uri.to_s } }
- end
-
- def test_parse_GIT
- @set.instance_variable_set :@install_dir, "install_dir"
-
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://example/a.git
- revision: abranch
- specs:
- a (2)
- b (>= 3)
- c
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 2")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- git_set = @set.sets.find do |set|
- Gem::Resolver::GitSet === set
- end
-
- assert git_set, "could not find a GitSet"
-
- assert_equal %w[a-2], git_set.specs.values.map(&:full_name)
-
- assert_equal [dep("b", ">= 3"), dep("c")],
- git_set.specs.values.first.dependencies
-
- expected = {
- "a" => %w[git://example/a.git abranch],
- }
-
- assert_equal expected, git_set.repositories
- assert_equal "install_dir", git_set.root_dir
- end
-
- def test_parse_GIT_branch
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://example/a.git
- revision: 1234abc
- branch: 0-9-12-stable
- specs:
- a (2)
- b (>= 3)
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 2")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- git_set = @set.sets.find do |set|
- Gem::Resolver::GitSet === set
- end
-
- assert git_set, "could not find a GitSet"
-
- expected = {
- "a" => %w[git://example/a.git 1234abc],
- }
-
- assert_equal expected, git_set.repositories
- end
-
- def test_parse_GIT_ref
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://example/a.git
- revision: 1234abc
- ref: 1234abc
- specs:
- a (2)
- b (>= 3)
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 2")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- git_set = @set.sets.find do |set|
- Gem::Resolver::GitSet === set
- end
-
- assert git_set, "could not find a GitSet"
-
- expected = {
- "a" => %w[git://example/a.git 1234abc],
- }
-
- assert_equal expected, git_set.repositories
- end
-
- def test_parse_GIT_tag
- write_lockfile <<-LOCKFILE
-GIT
- remote: git://example/a.git
- revision: 1234abc
- tag: v0.9.12
- specs:
- a (2)
- b (>= 3)
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 2")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- git_set = @set.sets.find do |set|
- Gem::Resolver::GitSet === set
- end
-
- assert git_set, "could not find a GitSet"
-
- expected = {
- "a" => %w[git://example/a.git 1234abc],
- }
-
- assert_equal expected, git_set.repositories
- end
-
- def test_parse_PATH
- _, _, directory = vendor_gem
-
- write_lockfile <<-LOCKFILE
-PATH
- remote: #{directory}
- specs:
- a (1)
- b (2)
-
-DEPENDENCIES
- a!
- LOCKFILE
-
- parse_lockfile @set, []
-
- assert_equal [dep("a", "= 1")], @set.dependencies
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set, "found a LockSet"
-
- vendor_set = @set.sets.find do |set|
- Gem::Resolver::VendorSet === set
- end
-
- assert vendor_set, "could not find a VendorSet"
-
- assert_equal %w[a-1], vendor_set.specs.values.map(&:full_name)
-
- spec = vendor_set.load_spec "a", nil, nil, nil
-
- assert_equal [dep("b", "= 2")], spec.dependencies
- end
-
- def test_parse_dependency
- write_lockfile " 1)"
-
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file @lock_file
- parser = tokenizer.make_parser nil, nil
-
- parsed = parser.parse_dependency "a", "="
-
- assert_equal dep("a", "= 1"), parsed
-
- write_lockfile ")"
-
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file @lock_file
- parser = tokenizer.make_parser nil, nil
-
- parsed = parser.parse_dependency "a", "2"
-
- assert_equal dep("a", "= 2"), parsed
- end
-
- def test_parse_gem_specs_dependency
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
- b (= 3)
- c (~> 4)
- d
- e (~> 5.0, >= 5.0.1)
- b (3-x86_64-linux)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- a
- LOCKFILE
-
- platforms = []
- parse_lockfile @set, platforms
-
- assert_equal [dep("a")], @set.dependencies
-
- assert_equal [Gem::Platform::RUBY], platforms
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- assert lockfile_set, "could not find a LockSet"
-
- assert_equal %w[a-2 b-3], lockfile_set.specs.map(&:full_name)
-
- expected = [
- Gem::Platform::RUBY,
- Gem::Platform.new("x86_64-linux"),
- ]
-
- assert_equal expected, lockfile_set.specs.map(&:platform)
-
- spec = lockfile_set.specs.first
-
- expected = [
- dep("b", "= 3"),
- dep("c", "~> 4"),
- dep("d"),
- dep("e", "~> 5.0", ">= 5.0.1"),
- ]
-
- assert_equal expected, spec.dependencies
- end
-
- def test_parse_missing
- assert_raise(Errno::ENOENT) do
- parse_lockfile @set, []
- end
-
- lockfile_set = @set.sets.find do |set|
- Gem::Resolver::LockSet === set
- end
-
- refute lockfile_set
- end
-
- def write_lockfile(lockfile)
- File.open @lock_file, "w" do |io|
- io.write lockfile
- end
- end
-
- def parse_lockfile(set, platforms)
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file @lock_file
- parser = tokenizer.make_parser set, platforms
- parser.parse
- end
-end
diff --git a/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb b/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb
deleted file mode 100644
index dce8c9ada5..0000000000
--- a/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb
+++ /dev/null
@@ -1,307 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helper"
-require "rubygems/request_set"
-require "rubygems/request_set/lockfile"
-require "rubygems/request_set/lockfile/tokenizer"
-require "rubygems/request_set/lockfile/parser"
-
-class TestGemRequestSetLockfileTokenizer < Gem::TestCase
- def setup
- super
-
- @gem_deps_file = "gem.deps.rb"
- @lock_file = File.expand_path "#{@gem_deps_file}.lock"
- end
-
- def test_peek
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n"
-
- assert_equal :newline, tokenizer.peek.first
-
- assert_equal :newline, tokenizer.next_token.first
-
- assert_equal :EOF, tokenizer.peek.first
- end
-
- def test_skip
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n"
-
- refute_predicate tokenizer, :empty?
-
- tokenizer.skip :newline
-
- assert_empty tokenizer
- end
-
- def test_token_pos
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new ""
- assert_equal [5, 0], tokenizer.token_pos(5)
-
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "", nil, 1, 2
- assert_equal [3, 1], tokenizer.token_pos(5)
- end
-
- def test_tokenize
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
- b (= 2)
- c (!= 3)
- d (> 4)
- e (< 5)
- f (>= 6)
- g (<= 7)
- h (~> 8)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- a
- LOCKFILE
-
- expected = [
- [:section, "GEM", 0, 0],
- [:newline, nil, 3, 0],
-
- [:entry, "remote", 2, 1],
- [:text, @gem_repo, 10, 1],
- [:newline, nil, 34, 1],
-
- [:entry, "specs", 2, 2],
- [:newline, nil, 8, 2],
-
- [:text, "a", 4, 3],
- [:l_paren, nil, 6, 3],
- [:text, "2", 7, 3],
- [:r_paren, nil, 8, 3],
- [:newline, nil, 9, 3],
-
- [:text, "b", 6, 4],
- [:l_paren, nil, 8, 4],
- [:requirement, "=", 9, 4],
- [:text, "2", 11, 4],
- [:r_paren, nil, 12, 4],
- [:newline, nil, 13, 4],
-
- [:text, "c", 6, 5],
- [:l_paren, nil, 8, 5],
- [:requirement, "!=", 9, 5],
- [:text, "3", 12, 5],
- [:r_paren, nil, 13, 5],
- [:newline, nil, 14, 5],
-
- [:text, "d", 6, 6],
- [:l_paren, nil, 8, 6],
- [:requirement, ">", 9, 6],
- [:text, "4", 11, 6],
- [:r_paren, nil, 12, 6],
- [:newline, nil, 13, 6],
-
- [:text, "e", 6, 7],
- [:l_paren, nil, 8, 7],
- [:requirement, "<", 9, 7],
- [:text, "5", 11, 7],
- [:r_paren, nil, 12, 7],
- [:newline, nil, 13, 7],
-
- [:text, "f", 6, 8],
- [:l_paren, nil, 8, 8],
- [:requirement, ">=", 9, 8],
- [:text, "6", 12, 8],
- [:r_paren, nil, 13, 8],
- [:newline, nil, 14, 8],
-
- [:text, "g", 6, 9],
- [:l_paren, nil, 8, 9],
- [:requirement, "<=", 9, 9],
- [:text, "7", 12, 9],
- [:r_paren, nil, 13, 9],
- [:newline, nil, 14, 9],
-
- [:text, "h", 6, 10],
- [:l_paren, nil, 8, 10],
- [:requirement, "~>", 9, 10],
- [:text, "8", 12, 10],
- [:r_paren, nil, 13, 10],
- [:newline, nil, 14, 10],
-
- [:newline, nil, 0, 11],
-
- [:section, "PLATFORMS", 0, 12],
- [:newline, nil, 9, 12],
-
- [:text, Gem::Platform::RUBY, 2, 13],
- [:newline, nil, 6, 13],
-
- [:newline, nil, 0, 14],
-
- [:section, "DEPENDENCIES", 0, 15],
- [:newline, nil, 12, 15],
-
- [:text, "a", 2, 16],
- [:newline, nil, 3, 16],
- ]
-
- assert_equal expected, tokenize_lockfile
- end
-
- def test_tokenize_capitals
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- Ab (2)
-
-PLATFORMS
- #{Gem::Platform::RUBY}
-
-DEPENDENCIES
- Ab
- LOCKFILE
-
- expected = [
- [:section, "GEM", 0, 0],
- [:newline, nil, 3, 0],
- [:entry, "remote", 2, 1],
- [:text, @gem_repo, 10, 1],
- [:newline, nil, 34, 1],
- [:entry, "specs", 2, 2],
- [:newline, nil, 8, 2],
- [:text, "Ab", 4, 3],
- [:l_paren, nil, 7, 3],
- [:text, "2", 8, 3],
- [:r_paren, nil, 9, 3],
- [:newline, nil, 10, 3],
- [:newline, nil, 0, 4],
- [:section, "PLATFORMS", 0, 5],
- [:newline, nil, 9, 5],
- [:text, Gem::Platform::RUBY, 2, 6],
- [:newline, nil, 6, 6],
- [:newline, nil, 0, 7],
- [:section, "DEPENDENCIES", 0, 8],
- [:newline, nil, 12, 8],
- [:text, "Ab", 2, 9],
- [:newline, nil, 4, 9],
- ]
-
- assert_equal expected, tokenize_lockfile
- end
-
- def test_tokenize_conflict_markers
- write_lockfile "<<<<<<<"
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- tokenize_lockfile
- end
-
- assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)",
- e.message
-
- write_lockfile "|||||||"
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- tokenize_lockfile
- end
-
- assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)",
- e.message
-
- write_lockfile "======="
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- tokenize_lockfile
- end
-
- assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)",
- e.message
-
- write_lockfile ">>>>>>>"
-
- e = assert_raise Gem::RequestSet::Lockfile::ParseError do
- tokenize_lockfile
- end
-
- assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)",
- e.message
- end
-
- def test_tokenize_git
- write_lockfile <<-LOCKFILE
-DEPENDENCIES
- a!
- LOCKFILE
-
- expected = [
- [:section, "DEPENDENCIES", 0, 0],
- [:newline, nil, 12, 0],
-
- [:text, "a", 2, 1],
- [:bang, nil, 3, 1],
- [:newline, nil, 4, 1],
- ]
-
- assert_equal expected, tokenize_lockfile
- end
-
- def test_tokenize_multiple
- write_lockfile <<-LOCKFILE
-GEM
- remote: #{@gem_repo}
- specs:
- a (2)
- b (~> 3.0, >= 3.0.1)
- LOCKFILE
-
- expected = [
- [:section, "GEM", 0, 0],
- [:newline, nil, 3, 0],
-
- [:entry, "remote", 2, 1],
- [:text, @gem_repo, 10, 1],
- [:newline, nil, 34, 1],
-
- [:entry, "specs", 2, 2],
- [:newline, nil, 8, 2],
-
- [:text, "a", 4, 3],
- [:l_paren, nil, 6, 3],
- [:text, "2", 7, 3],
- [:r_paren, nil, 8, 3],
- [:newline, nil, 9, 3],
-
- [:text, "b", 6, 4],
- [:l_paren, nil, 8, 4],
- [:requirement, "~>", 9, 4],
- [:text, "3.0", 12, 4],
- [:comma, nil, 15, 4],
- [:requirement, ">=", 17, 4],
- [:text, "3.0.1", 20, 4],
- [:r_paren, nil, 25, 4],
- [:newline, nil, 26, 4],
- ]
-
- assert_equal expected, tokenize_lockfile
- end
-
- def test_unget
- tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n"
- tokenizer.unshift :token
- parser = tokenizer.make_parser nil, nil
-
- assert_equal :token, parser.get
- end
-
- def write_lockfile(lockfile)
- File.open @lock_file, "w" do |io|
- io.write lockfile
- end
- end
-
- def tokenize_lockfile
- Gem::RequestSet::Lockfile::Tokenizer.from_file(@lock_file).to_a
- end
-end
diff --git a/test/rubygems/test_gem_safe_yaml.rb b/test/rubygems/test_gem_safe_yaml.rb
index d6fef1d7de..8d0ac63c41 100644
--- a/test/rubygems/test_gem_safe_yaml.rb
+++ b/test/rubygems/test_gem_safe_yaml.rb
@@ -70,6 +70,19 @@ class TestGemSafeYAML < Gem::TestCase
assert_match(/unspecified class/, exception.message)
end
+ def test_plain_tag_key_does_not_construct_specification
+ yaml = <<~YAML
+ tag: "!ruby/object:Gem::Specification"
+ name: pwned
+ arbitrary_ivar: hello
+ YAML
+
+ result = Gem::SafeYAML.safe_load(yaml)
+ assert_kind_of Hash, result
+ assert_equal "!ruby/object:Gem::Specification", result["tag"]
+ assert_equal "pwned", result["name"]
+ end
+
def test_disallowed_symbol_rejected
yaml = <<~YAML
--- !ruby/object:Gem::Dependency
@@ -94,6 +107,66 @@ class TestGemSafeYAML < Gem::TestCase
assert_match(/unspecified class/, exception.message)
end
+ def test_disallowed_symbol_not_interned
+ unique = "rejected_symbol_#{rand(1 << 30)}"
+ yaml = <<~YAML
+ --- !ruby/object:Gem::Dependency
+ name: test
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 0
+ type: :#{unique}
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: 0
+ YAML
+
+ assert_raise(Psych::DisallowedClass) do
+ Gem::YAMLSerializer.load(yaml,
+ permitted_classes: Gem::SafeYAML::PERMITTED_CLASSES,
+ permitted_symbols: Gem::SafeYAML::PERMITTED_SYMBOLS)
+ end
+ refute_includes Symbol.all_symbols.map(&:to_s), unique
+ end
+
+ def test_inline_array_nesting_capped
+ depth = Gem::YAMLSerializer::Parser::MAX_NESTING_DEPTH + 1
+ yaml = "x: " + ("[" * depth) + "a" + ("]" * depth) + "\n"
+
+ expected = [Psych::SyntaxError]
+ # JRuby's JVM stack overflows before the Ruby-level nesting cap fires.
+ expected << ::Java::JavaLang::StackOverflowError if RUBY_ENGINE == "jruby"
+
+ assert_raise(*expected) do
+ Gem::YAMLSerializer.load(yaml, permitted_classes: [])
+ end
+ end
+
+ def test_unknown_alias_raises
+ yaml = <<~YAML
+ foo: 1
+ bar: *missing
+ YAML
+
+ expected_error = defined?(Psych::AnchorNotDefined) ? Psych::AnchorNotDefined : Psych::BadAlias
+ assert_raise(expected_error) { Gem::SafeYAML.safe_load(yaml) }
+ end
+
+ def test_unused_anchor_with_aliases_disabled_is_allowed
+ aliases_enabled = Gem::SafeYAML.aliases_enabled?
+ Gem::SafeYAML.aliases_enabled = false
+
+ result = Gem::SafeYAML.safe_load("foo: &unused 1\nbar: 2\n")
+ assert_equal({ "foo" => 1, "bar" => 2 }, result)
+ ensure
+ Gem::SafeYAML.aliases_enabled = aliases_enabled
+ end
+
def test_yaml_serializer_aliases_disabled
aliases_enabled = Gem::SafeYAML.aliases_enabled?
Gem::SafeYAML.aliases_enabled = false
diff --git a/tool/bundler/dev_gems.rb b/tool/bundler/dev_gems.rb
index bb1e64742c..c8e4d5345c 100644
--- a/tool/bundler/dev_gems.rb
+++ b/tool/bundler/dev_gems.rb
@@ -5,7 +5,7 @@ source "https://rubygems.org"
gem "test-unit", "~> 3.0"
gem "test-unit-ruby-core"
gem "rake", "~> 13.1"
-gem "rb_sys", ">= 0.9.127"
+gem "rb_sys", ">= 0.9.128"
gem "turbo_tests", "~> 2.2.3"
gem "parallel_tests", "~> 4.10.1"
diff --git a/tool/bundler/dev_gems.rb.lock b/tool/bundler/dev_gems.rb.lock
index 49c43fe84a..ee91c8baff 100644
--- a/tool/bundler/dev_gems.rb.lock
+++ b/tool/bundler/dev_gems.rb.lock
@@ -35,7 +35,7 @@ GEM
racc (1.8.1-java)
rake (13.4.2)
rake-compiler-dock (1.12.0)
- rb_sys (0.9.127)
+ rb_sys (0.9.128)
rake-compiler-dock (= 1.12.0)
rexml (3.4.4)
ronn-ng (0.10.1)
@@ -90,7 +90,7 @@ DEPENDENCIES
parallel (~> 1.19)
parallel_tests (~> 4.10.1)
rake (~> 13.1)
- rb_sys (>= 0.9.127)
+ rb_sys (>= 0.9.128)
ronn-ng (~> 0.10.1)
rspec-core (~> 3.12)
rspec-expectations (~> 3.12)
@@ -124,7 +124,7 @@ CHECKSUMS
racc (1.8.1-java) sha256=54f2e6d1e1b91c154013277d986f52a90e5ececbe91465d29172e49342732b98
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
rake-compiler-dock (1.12.0) sha256=f13205c2738f3d2053afcd03491a9e4541b22a59a0bfc53fc8bc883bd8188023
- rb_sys (0.9.127) sha256=e9f90df3bb0577472d26d96127d5b5774b98f44de881e7d36aeefd28d6337847
+ rb_sys (0.9.128) sha256=9ab81f4d6d4e1895de18762232362d1264475aa7035756b50441e442130538fd
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
ronn-ng (0.10.1) sha256=4eeb0185c0fbfa889efed923b5b50e949cd869e7d82ac74138acd0c9c7165ec0
rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
diff --git a/tool/bundler/rubocop_gems.rb b/tool/bundler/rubocop_gems.rb
index 4608228ced..c71b862318 100644
--- a/tool/bundler/rubocop_gems.rb
+++ b/tool/bundler/rubocop_gems.rb
@@ -10,4 +10,4 @@ gem "rake"
gem "rake-compiler"
gem "rspec"
gem "test-unit"
-gem "rb_sys", ">= 0.9.127"
+gem "rb_sys", ">= 0.9.128"
diff --git a/tool/bundler/rubocop_gems.rb.lock b/tool/bundler/rubocop_gems.rb.lock
index 170c636cc7..f265e7c9eb 100644
--- a/tool/bundler/rubocop_gems.rb.lock
+++ b/tool/bundler/rubocop_gems.rb.lock
@@ -42,7 +42,7 @@ GEM
rake-compiler (1.3.1)
rake
rake-compiler-dock (1.12.0)
- rb_sys (0.9.127)
+ rb_sys (0.9.128)
rake-compiler-dock (= 1.12.0)
rdoc (7.2.0)
erb
@@ -103,7 +103,7 @@ DEPENDENCIES
minitest (~> 5.1)
rake
rake-compiler
- rb_sys (>= 0.9.127)
+ rb_sys (>= 0.9.128)
rspec
rubocop (>= 1.52.1, < 2)
test-unit
@@ -138,7 +138,7 @@ CHECKSUMS
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
rake-compiler (1.3.1) sha256=6b351612b6e2d73ddd5563ee799bb58685176e05363db6758504bd11573d670a
rake-compiler-dock (1.12.0) sha256=f13205c2738f3d2053afcd03491a9e4541b22a59a0bfc53fc8bc883bd8188023
- rb_sys (0.9.127) sha256=e9f90df3bb0577472d26d96127d5b5774b98f44de881e7d36aeefd28d6337847
+ rb_sys (0.9.128) sha256=9ab81f4d6d4e1895de18762232362d1264475aa7035756b50441e442130538fd
rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192
regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb
reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
diff --git a/tool/bundler/standard_gems.rb b/tool/bundler/standard_gems.rb
index 86abf1375f..84028a385d 100644
--- a/tool/bundler/standard_gems.rb
+++ b/tool/bundler/standard_gems.rb
@@ -10,4 +10,4 @@ gem "rake"
gem "rake-compiler"
gem "rspec"
gem "test-unit"
-gem "rb_sys", ">= 0.9.127"
+gem "rb_sys", ">= 0.9.128"
diff --git a/tool/bundler/standard_gems.rb.lock b/tool/bundler/standard_gems.rb.lock
index 1f3d22f86e..8ef7806bcc 100644
--- a/tool/bundler/standard_gems.rb.lock
+++ b/tool/bundler/standard_gems.rb.lock
@@ -42,7 +42,7 @@ GEM
rake-compiler (1.3.1)
rake
rake-compiler-dock (1.12.0)
- rb_sys (0.9.127)
+ rb_sys (0.9.128)
rake-compiler-dock (= 1.12.0)
rdoc (7.2.0)
erb
@@ -119,7 +119,7 @@ DEPENDENCIES
minitest (~> 5.1)
rake
rake-compiler
- rb_sys (>= 0.9.127)
+ rb_sys (>= 0.9.128)
rspec
standard (~> 1.0)
test-unit
@@ -154,7 +154,7 @@ CHECKSUMS
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
rake-compiler (1.3.1) sha256=6b351612b6e2d73ddd5563ee799bb58685176e05363db6758504bd11573d670a
rake-compiler-dock (1.12.0) sha256=f13205c2738f3d2053afcd03491a9e4541b22a59a0bfc53fc8bc883bd8188023
- rb_sys (0.9.127) sha256=e9f90df3bb0577472d26d96127d5b5774b98f44de881e7d36aeefd28d6337847
+ rb_sys (0.9.128) sha256=9ab81f4d6d4e1895de18762232362d1264475aa7035756b50441e442130538fd
rdoc (7.2.0) sha256=8650f76cd4009c3b54955eb5d7e3a075c60a57276766ebf36f9085e8c9f23192
regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb
reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
diff --git a/tool/bundler/test_gems.rb b/tool/bundler/test_gems.rb
index fc3ccf4f56..384ff85d1f 100644
--- a/tool/bundler/test_gems.rb
+++ b/tool/bundler/test_gems.rb
@@ -8,7 +8,7 @@ gem "compact_index", "~> 0.15.0"
gem "sinatra", "~> 4.1"
gem "rake", "~> 13.1"
gem "builder", "~> 3.2"
-gem "rb_sys", ">= 0.9.127"
+gem "rb_sys", ">= 0.9.128"
gem "fiddle"
gem "rubygems-generate_index", "~> 1.1"
gem "concurrent-ruby"
diff --git a/tool/bundler/test_gems.rb.lock b/tool/bundler/test_gems.rb.lock
index bb5dcbb581..a8352f3070 100644
--- a/tool/bundler/test_gems.rb.lock
+++ b/tool/bundler/test_gems.rb.lock
@@ -31,7 +31,7 @@ GEM
rack (>= 1.3)
rake (13.4.2)
rake-compiler-dock (1.12.0)
- rb_sys (0.9.127)
+ rb_sys (0.9.128)
rake-compiler-dock (= 1.12.0)
rubygems-generate_index (1.1.3)
compact_index (~> 0.15.0)
@@ -66,7 +66,7 @@ DEPENDENCIES
rack (~> 3.1)
rack-test (~> 2.1)
rake (~> 13.1)
- rb_sys (>= 0.9.127)
+ rb_sys (>= 0.9.128)
rubygems-generate_index (~> 1.1)
shellwords
sinatra (~> 4.1)
@@ -92,7 +92,7 @@ CHECKSUMS
rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
rake-compiler-dock (1.12.0) sha256=f13205c2738f3d2053afcd03491a9e4541b22a59a0bfc53fc8bc883bd8188023
- rb_sys (0.9.127) sha256=e9f90df3bb0577472d26d96127d5b5774b98f44de881e7d36aeefd28d6337847
+ rb_sys (0.9.128) sha256=9ab81f4d6d4e1895de18762232362d1264475aa7035756b50441e442130538fd
rubygems-generate_index (1.1.3) sha256=3571424322666598e9586a906485e1543b617f87644913eaf137d986a3393f5c
shellwords (0.2.2) sha256=b8695a791de2f71472de5abdc3f4332f6535a4177f55d8f99e7e44266cd32f94
sinatra (4.2.1) sha256=b7aeb9b11d046b552972ade834f1f9be98b185fa8444480688e3627625377080
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index ddd164425d..86078f4ac8 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -4147,7 +4147,6 @@ impl Function {
if let Some(replacement) = (props.inline)(self, tmp_block, recv, &args, state) {
// Copy contents of tmp_block to block
assert_ne!(block, tmp_block);
- emit_super_call_guards(self, block, super_cme, current_cme, mid, state);
let insns = std::mem::take(&mut self.blocks[tmp_block.0].insns);
self.blocks[block.0].insns.extend(insns);
self.count(block, Counter::inline_cfunc_optimized_send_count);
diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs
index 2c992a8725..74c0af710e 100644
--- a/zjit/src/hir/opt_tests.rs
+++ b/zjit/src/hir/opt_tests.rs
@@ -10010,11 +10010,6 @@ mod hir_opt_tests {
v20:CallableMethodEntry[VALUE(0x1040)] = GuardBitEquals v19, Value(VALUE(0x1040))
v21:RubyValue = LoadField v18, :VM_ENV_DATA_INDEX_SPECVAL@0x1048
v22:FalseClass = GuardBitEquals v21, Value(false)
- v30:CPtr = GetEP 0
- v31:RubyValue = LoadField v30, :VM_ENV_DATA_INDEX_ME_CREF@0x1038
- v32:CallableMethodEntry[VALUE(0x1040)] = GuardBitEquals v31, Value(VALUE(0x1040))
- v33:RubyValue = LoadField v30, :VM_ENV_DATA_INDEX_SPECVAL@0x1048
- v34:FalseClass = GuardBitEquals v33, Value(false)
v23:Array = GuardType v6, Array
v24:CUInt64 = LoadField v23, :RBASIC_FLAGS@0x1049
v25:CUInt64 = GuardNoBitsSet v24, RUBY_FL_FREEZE=CUInt64(2048)
@@ -10054,11 +10049,6 @@ mod hir_opt_tests {
v25:CallableMethodEntry[VALUE(0x1048)] = GuardBitEquals v24, Value(VALUE(0x1048))
v26:RubyValue = LoadField v23, :VM_ENV_DATA_INDEX_SPECVAL@0x1050
v27:FalseClass = GuardBitEquals v26, Value(false)
- v38:CPtr = GetEP 0
- v39:RubyValue = LoadField v38, :VM_ENV_DATA_INDEX_ME_CREF@0x1040
- v40:CallableMethodEntry[VALUE(0x1048)] = GuardBitEquals v39, Value(VALUE(0x1048))
- v41:RubyValue = LoadField v38, :VM_ENV_DATA_INDEX_SPECVAL@0x1050
- v42:FalseClass = GuardBitEquals v41, Value(false)
v28:Array = GuardType v9, Array
v29:Fixnum = GuardType v10, Fixnum
v30:CInt64 = UnboxFixnum v29