diff options
author | Martin Emde <martin.emde@gmail.com> | 2023-08-15 10:39:46 -0700 |
---|---|---|
committer | git <svn-admin@ruby-lang.org> | 2023-08-17 23:16:57 +0000 |
commit | e913431687f2fffb1a8cc435e60c95eea887b087 (patch) | |
tree | 1df72eed6c68958b0d38efe6d9600541a446da4e /lib/rubygems/package/tar_reader | |
parent | e504c368943acd489c9be5bc249425e885605ff1 (diff) |
[rubygems/rubygems] Raise Gem::Package::FormatError on EOF, indicating corrupt gem
Gem::Package::TarReader::Entry now raises EOFError or returns nil
appropriately based on Ruby core IO.read and IO.readpartial behavior.
Zlib will respond accordingly by raising Zlib::GzipFile::Error on EOF.
When verifying a gem or extracting contents, raise FormatError similar
to other cases of corrupt gems.
Addresses a bug where Gem::Package would attempt to call size on nil
instead of raising a more descriptive and useful error, leading users
to assume the problem is internal to rubygems.
Remove unused error class TarReader::UnexpectedEOF that was never raised
since the NoMethodError on nil would happen first. Use EOFError instead.
https://github.com/rubygems/rubygems/commit/dc6129644b
Diffstat (limited to 'lib/rubygems/package/tar_reader')
-rw-r--r-- | lib/rubygems/package/tar_reader/entry.rb | 38 |
1 files changed, 18 insertions, 20 deletions
diff --git a/lib/rubygems/package/tar_reader/entry.rb b/lib/rubygems/package/tar_reader/entry.rb index e22efa95b3..5e9d9af5c6 100644 --- a/lib/rubygems/package/tar_reader/entry.rb +++ b/lib/rubygems/package/tar_reader/entry.rb @@ -102,9 +102,7 @@ class Gem::Package::TarReader::Entry # Read one byte from the tar entry def getc - check_closed - - return nil if @read >= @header.size + return nil if eof? ret = @io.getc @read += 1 if ret @@ -156,30 +154,28 @@ class Gem::Package::TarReader::Entry alias_method :length, :size ## - # Reads +len+ bytes from the tar file entry, or the rest of the entry if - # nil - - def read(len = nil) - check_closed - - len ||= @header.size - @read + # Reads +maxlen+ bytes from the tar file entry, or the rest of the entry if nil - return nil if len > 0 && @read >= @header.size + def read(maxlen = nil) + if eof? + return maxlen.to_i.zero? ? "" : nil + end - max_read = [len, @header.size - @read].min + max_read = [maxlen, @header.size - @read].compact.min ret = @io.read max_read + if ret.nil? + return maxlen ? nil : "" # IO.read returns nil on EOF with len argument + end @read += ret.size ret end - def readpartial(maxlen = nil, outbuf = "".b) - check_closed - - maxlen ||= @header.size - @read - - raise EOFError if maxlen > 0 && @read >= @header.size + def readpartial(maxlen, outbuf = "".b) + if eof? && maxlen > 0 + raise EOFError, "end of file reached" + end max_read = [maxlen, @header.size - @read].min @@ -213,6 +209,8 @@ class Gem::Package::TarReader::Entry pending = new_pos - @io.pos + return 0 if pending == 0 + if @io.respond_to?(:seek) begin # avoid reading if the @io supports seeking @@ -230,8 +228,8 @@ class Gem::Package::TarReader::Entry end while pending > 0 do - size_read = @io.read([pending, 4096].min).size - raise UnexpectedEOF if @io.eof? + size_read = @io.read([pending, 4096].min)&.size + raise(EOFError, "end of file reached") if size_read.nil? pending -= size_read end |