ruby / ruby/rubygems

Bundler.bin_path writes to the filesystem when it should be an attribute reader

Open
#9,197 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bundler
Dominant language
Ruby
Stars
4k
Forks
1.9k
Avg merge
1d 2h
Merged PRs (30d)
81

Description

Describe the problem as clearly as you can

Bundler.bin_path looks like a simple attribute reader, is documented as such, but performs filesystem writes:

https://github.com/ruby/rubygems/blob/570c3419c7f111d8665710f4e2cb15ca878e606d/bundler/lib/bundler.rb#L119-L126

    # Returns absolute location of where binstubs are installed to.
    def bin_path
      @bin_path ||= begin
        path = Bundler.settings[:bin] || "bin"
        path = Pathname.new(path).expand_path(root).expand_path
        mkdir_p(path)
        path
      end
    end

The writes fail on read-only filesystems, and writing to filesystem is not expected behavior when one is trying to find out "where binstubs are installed to".

More information: https://github.com/DataDog/dd-trace-rb/issues/5137

Did you try upgrading rubygems & bundler?

Problematic code is in master

Post steps to reproduce the problem
big# modprobe zram
big# zramctl -s 1g -f
/dev/zram0
big# mkfs.ext2 /dev/zram0 
mke2fs 1.46.5 (30-Dec-2021)
Discarding device blocks: done                            
Creating filesystem with 262144 4k blocks and 65536 inodes
Filesystem UUID: 35fbb153-fd4e-4637-b912-5df653bbf4bb
Superblock backups stored on blocks: 
        32768, 98304, 163840, 229376

Allocating group tables: done                            
Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done

big# mount -o ro /dev/zram0 /mnt/tmp 
big# su - sandbox
big% bundle config bin /mnt/tmp/bin
big% echo 'source "https://rubygems.org"' >Gemfile
big% irb -rbundler                                
irb(main):001:0> Bundler.bin_path
/usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/shared_helpers.rb:117:in `rescue in filesystem_access': There was an error accessing `/mnt/tmp/bin`. (Bundler::GenericSystemCallError)
The underlying system error is Errno::EROFS: Read-only file system @ dir_s_mkdir - /mnt/tmp/bin
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/shared_helpers.rb:102:in `filesystem_access'
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler.rb:109:in `bin_path'
        from (irb):1:in `<main>'
        from /usr/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>'
        from /usr/bin/irb:23:in `load'
        from /usr/bin/irb:23:in `<main>'
/usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/vendor/fileutils/lib/fileutils.rb:250:in `mkdir': Read-only file system @ dir_s_mkdir - /mnt/tmp/bin (Errno::EROFS)
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/vendor/fileutils/lib/fileutils.rb:250:in `fu_mkdir'
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/vendor/fileutils/lib/fileutils.rb:228:in `block (2 levels) in mkdir_p'
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/vendor/fileutils/lib/fileutils.rb:226:in `reverse_each'
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/vendor/fileutils/lib/fileutils.rb:226:in `block in mkdir_p'
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/vendor/fileutils/lib/fileutils.rb:211:in `each'
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/vendor/fileutils/lib/fileutils.rb:211:in `mkdir_p'
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler.rb:109:in `block in bin_path'
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler/shared_helpers.rb:103:in `filesystem_access'
        from /usr/share/rubygems-integration/all/gems/bundler-2.3.5/lib/bundler.rb:109:in `bin_path'
        from (irb):1:in `<main>'
        from /usr/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>'
        from /usr/bin/irb:23:in `load'
        from /usr/bin/irb:23:in `<main>'
Which command did you run?
What were you expecting to happen?

Bundler.bin_path should return the bin path and not perform any filesystem writes.

What happened instead?

Bundler writes (tries to write) to the filesystem.

Replace this with the actual result you got. Paste the output of your command here.
If not included with the output of your command, run bundle env and paste the output below

Not relevant

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Bundler.bin_path in bundler/lib/bundler.rb around lines 119-126 and review the linked reproduction using a read-only filesystem. Done means Bundler.bin_path returns the configured, expanded bin path without attempting filesystem writes, including when the target path does not exist.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
tooling
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.