summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Giddins <[email protected]>2023-08-21 09:13:43 -0700
committergit <[email protected]>2023-09-20 02:03:02 +0000
commite52f9bd41e1c407ac675fa3d1fbaabec854f6968 (patch)
treedfa011021ed57acb4312e072c520cd318d9f81d4
parentf0d1b0cc4b5a99de9dc709b8f43d8be8e18c7323 (diff)
[rubygems/rubygems] Bundler error handling
https://github.com/rubygems/rubygems/commit/63b422b71a
-rw-r--r--lib/bundler.rb6
-rw-r--r--lib/bundler/fetcher.rb4
-rw-r--r--lib/bundler/rubygems_integration.rb4
-rw-r--r--lib/rubygems/safe_marshal.rb2
-rw-r--r--lib/rubygems/safe_marshal/reader.rb49
-rw-r--r--lib/rubygems/safe_marshal/visitors/to_ruby.rb13
-rw-r--r--spec/bundler/bundler/bundler_spec.rb2
7 files changed, 66 insertions, 14 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 85929c56aa..ee08a2dab8 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -517,7 +517,11 @@ EOF
def safe_load_marshal(data)
if Gem.respond_to?(:load_safe_marshal)
Gem.load_safe_marshal
- Gem::SafeMarshal.safe_load(data)
+ begin
+ Gem::SafeMarshal.safe_load(data)
+ rescue Gem::SafeMarshal::Reader::Error, Gem::SafeMarshal::Visitors::ToRuby::Error => e
+ raise MarshalError, "#{e.class}: #{e.message}"
+ end
else
load_marshal(data, :marshal_proc => SafeMarshal.proc)
end
diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb
index 9b64a3c771..5c1eac415e 100644
--- a/lib/bundler/fetcher.rb
+++ b/lib/bundler/fetcher.rb
@@ -111,7 +111,7 @@ module Bundler
spec_file_name = "#{spec.join "-"}.gemspec"
uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz")
- if uri.scheme == "file"
+ spec = if uri.scheme == "file"
path = Bundler.rubygems.correct_for_windows_path(uri.path)
Bundler.safe_load_marshal Bundler.rubygems.inflate(Gem.read_binary(path))
elsif cached_spec_path = gemspec_cached_path(spec_file_name)
@@ -119,6 +119,8 @@ module Bundler
else
Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body)
end
+ raise MarshalError, "is #{spec.inspect}" unless spec.is_a?(Gem::Specification)
+ spec
rescue MarshalError
raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \
"Your network or your gem server is probably having issues right now."
diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb
index d6f179cc96..f6f0d4a804 100644
--- a/lib/bundler/rubygems_integration.rb
+++ b/lib/bundler/rubygems_integration.rb
@@ -496,7 +496,9 @@ module Bundler
fetcher = gem_remote_fetcher
fetcher.headers = { "X-Gemfile-Source" => remote.original_uri.to_s } if remote.original_uri
string = fetcher.fetch_path(path)
- Bundler.safe_load_marshal(string)
+ specs = Bundler.safe_load_marshal(string)
+ raise MarshalError, "Specs #{name} from #{remote} is expected to be an Array but was unexpected class #{specs.class}" unless specs.is_a?(Array)
+ specs
rescue Gem::RemoteFetcher::FetchError
# it's okay for prerelease to fail
raise unless name == "prerelease_specs"
diff --git a/lib/rubygems/safe_marshal.rb b/lib/rubygems/safe_marshal.rb
index 215f851167..d308f2d65f 100644
--- a/lib/rubygems/safe_marshal.rb
+++ b/lib/rubygems/safe_marshal.rb
@@ -62,7 +62,7 @@ module Gem
end
def self.load(input, permitted_classes: [::Symbol], permitted_symbols: [], permitted_ivars: {})
- root = Reader.new(StringIO.new(input, "r")).read!
+ root = Reader.new(StringIO.new(input, "r").binmode).read!
Visitors::ToRuby.new(
permitted_classes: permitted_classes,
diff --git a/lib/rubygems/safe_marshal/reader.rb b/lib/rubygems/safe_marshal/reader.rb
index 105984ff04..bc0bb62986 100644
--- a/lib/rubygems/safe_marshal/reader.rb
+++ b/lib/rubygems/safe_marshal/reader.rb
@@ -5,7 +5,16 @@ require_relative "elements"
module Gem
module SafeMarshal
class Reader
- class UnconsumedBytesError < StandardError
+ class Error < StandardError
+ end
+
+ class UnsupportedVersionError < Error
+ end
+
+ class UnconsumedBytesError < Error
+ end
+
+ class NotImplementedError < Error
end
def initialize(io)
@@ -26,7 +35,7 @@ module Gem
def read_header
v = @io.read(2)
- raise "Unsupported marshal version #{v.inspect}, expected #{MARSHAL_VERSION.inspect}" unless v == MARSHAL_VERSION
+ raise UnsupportedVersionError, "Unsupported marshal version #{v.bytes.map(&:ord).join(".")}, expected #{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}" unless v == MARSHAL_VERSION
end
def read_byte
@@ -80,7 +89,7 @@ module Gem
when 91 then read_array # ?[
when 102 then read_float # ?f
when 105 then Elements::Integer.new int: read_integer # ?i
- when 108 then read_bignum
+ when 108 then read_bignum # ?l
when 111 then read_object # ?o
when 117 then read_user_defined # ?u
when 123 then read_hash # ?{
@@ -94,7 +103,7 @@ module Gem
when "S".ord then read_struct
when "C".ord then read_user_class
else
- raise "Unsupported marshal type discriminator #{type.chr.inspect} (#{type})"
+ raise Error, "Unknown marshal type discriminator #{type.chr.inspect} (#{type})"
end
end
@@ -177,6 +186,38 @@ module Gem
def read_bignum
Elements::Bignum.new(sign: read_byte, data: @io.read(read_integer * 2))
end
+
+ def read_extended_object
+ raise NotImplementedError, "Reading Marshal objects of type extended_object is not implemented"
+ end
+
+ def read_class
+ raise NotImplementedError, "Reading Marshal objects of type class is not implemented"
+ end
+
+ def read_module
+ raise NotImplementedError, "Reading Marshal objects of type module is not implemented"
+ end
+
+ def read_class_or_module
+ raise NotImplementedError, "Reading Marshal objects of type class_or_module is not implemented"
+ end
+
+ def read_data
+ raise NotImplementedError, "Reading Marshal objects of type data is not implemented"
+ end
+
+ def read_regexp
+ raise NotImplementedError, "Reading Marshal objects of type regexp is not implemented"
+ end
+
+ def read_struct
+ raise NotImplementedError, "Reading Marshal objects of type struct is not implemented"
+ end
+
+ def read_user_class
+ raise NotImplementedError, "Reading Marshal objects of type user_class is not implemented"
+ end
end
end
end
diff --git a/lib/rubygems/safe_marshal/visitors/to_ruby.rb b/lib/rubygems/safe_marshal/visitors/to_ruby.rb
index fb0c75598c..92b647438b 100644
--- a/lib/rubygems/safe_marshal/visitors/to_ruby.rb
+++ b/lib/rubygems/safe_marshal/visitors/to_ruby.rb
@@ -305,7 +305,10 @@ module Gem::SafeMarshal
raise MethodCallError, "Unable to call #{method.inspect} on #{receiver.inspect}, perhaps it is a class using marshal compat, which is not visible in ruby? #{e}"
end
- class UnpermittedSymbolError < StandardError
+ class Error < StandardError
+ end
+
+ class UnpermittedSymbolError < Error
def initialize(symbol:, stack:)
@symbol = symbol
@stack = stack
@@ -313,7 +316,7 @@ module Gem::SafeMarshal
end
end
- class UnpermittedIvarError < StandardError
+ class UnpermittedIvarError < Error
def initialize(symbol:, klass:, stack:)
@symbol = symbol
@klass = klass
@@ -322,7 +325,7 @@ module Gem::SafeMarshal
end
end
- class UnpermittedClassError < StandardError
+ class UnpermittedClassError < Error
def initialize(name:, stack:)
@name = name
@stack = stack
@@ -330,10 +333,10 @@ module Gem::SafeMarshal
end
end
- class FormatError < StandardError
+ class FormatError < Error
end
- class MethodCallError < StandardError
+ class MethodCallError < Error
end
end
end
diff --git a/spec/bundler/bundler/bundler_spec.rb b/spec/bundler/bundler/bundler_spec.rb
index f4c1664620..132ce5c8ad 100644
--- a/spec/bundler/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler/bundler_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Bundler do
end
it "loads simple structure" do
- simple_structure = { "name" => [:abc] }
+ simple_structure = { "name" => [:development] }
data = Marshal.dump(simple_structure)
expect(Bundler.safe_load_marshal(data)).to eq(simple_structure)
end