ml.ruby-lang.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

ruby-core

Thread Start a new thread
Download
Threads by month
  • ----- 2026 -----
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
ruby-core@ml.ruby-lang.org

October 2024

  • 6 participants
  • 205 discussions
[ruby-core:119595] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
by zverok (Victor Shepelev) 23 Oct '24

23 Oct '24
Issue #15381 has been updated by zverok (Victor Shepelev). > I think that would be awesome. If I do `other_method(**model)` and that model is representable as a hash, passing it as keyword arguments is beautiful. ...until you passed it erroneously, and it was never meant to be, and the error happened not where it should happen but in some completely different place. ...until somebody tries to make heads or tails from the legacy codebase and assumes that something that is invoked with `**value` is hash-like, while in fact, it was a value object, and there is no way to know it without chasing it back and forth by call stack. Now, _imagine_ if that was the author’s intention (“here we unpack our model into the keyword args”) and the author just wrote (like, five more characters) ```ruby other_method(**model.to_h) ``` ...and the reader immediately sees where the “transition point” is from value object/model to keyword args/hash-like data. > Imagine something like > ```ruby > ValidOptions = Struct.new(:ssl, :host, :port) > ``` Now imagine that if you want to have such options as kwarg-passable, you can just ```ruby ValidOptions = Struct.new(:ssl, :host, :port) { alias to_hash to_h } ``` ...and that immediately communicates “this particular value object (unlike many other value objects) thinks of it as a hash-like object that would be unpacked probably at some point”. >> problem of things being unintentionally unpacked, considering how many objects have to_h method > > That never happens. I have never ever written code where `foo(**opts)` throws "no implicit conversion of Object into Hash" and then I realize I really meant to use something other than opts. I saw this a lot (especially transitioning from older to newer syntaxes, libraries, and Ruby versions). Fighting anecdata with anecdata! :) The conversion from “it had just one extra parameter” to “it has a hash of extra parameters” is a frequent refactoring when some library matures, and I really like to have it reported to me early that some object passed where it doesn’t correspond to the target method’s expectations. `NoMethodError`/“no implicit conversion” is a wonderful tool for this, but only if it happens _in the closest place to the possible error_. PS: Honestly, I am still not sure which _problem_ we are trying to solve (that is not covered by the `**nil` addition) that is so frequent and has no other easy solution to be worth all the drawbacks. ---------------------------------------- Feature #15381: Let double splat call `to_h` implicitly https://bugs.ruby-lang.org/issues/15381#change-110217 * Author: sawa (Tsuyoshi Sawada) * Status: Open ---------------------------------------- The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal: ```ruby a = [ *(:foo if some_condition), *(:bar if another_condition), ] ``` And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol: ```ruby some_method(&:some_method_name) ``` Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows: ```ruby h = { **({a: 1} if some_condition), **({b: 2) if another_condition), } ``` There may be some other benefits of this feature that I have not noticed yet. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:119572] [Ruby master Bug#20807] String#gsub fails when called from string subclass with a block passed
by koilanetroc (Oleg Tolmashov) 23 Oct '24

23 Oct '24
Issue #20807 has been reported by koilanetroc (Oleg Tolmashov). ---------------------------------------- Bug #20807: String#gsub fails when called from string subclass with a block passed https://bugs.ruby-lang.org/issues/20807 * Author: koilanetroc (Oleg Tolmashov) * Status: Open * ruby -v: ruby 3.3.4 (2024-07-09 revision be1089c8ec) [arm64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- When `String#gsub` is called from a string subclass with a block, `Regexp.last_match` is nil, but passed block is executed. Here is example code: ```ruby def call_gsub(str) str.gsub(/%/) do puts "checking #{str.class}" puts "Special variable value: #{$&}" puts "Regexp.last_match = #{Regexp.last_match.inspect}\n\n" raise "Special variable $& is not assigned, but block is called" if $&.nil? end end class MyString < String def gsub(*args, &block) super(*args, &block) # just forward everything end end text = 'test%text_with_special_character' call_gsub(String.new(text)) # original string call_gsub(MyString.new(text)) # string subclass ``` Result: ``` checking String Special variable value: % Regexp.last_match = #<MatchData "%"> checking MyString Special variable value: Regexp.last_match = nil gsub_bug.rb:7:in `block in call_gsub': Special variable $& is not assigned, but block is called (RuntimeError) from gsub_bug.rb:13:in `gsub' from gsub_bug.rb:13:in `gsub' from gsub_bug.rb:2:in `call_gsub' from gsub_bug.rb:20:in `<main>' ``` I expect result to be the same for both classes since `MyString` just wraps the same method: ``` checking String Special variable value: % Regexp.last_match = #<MatchData "%"> checking MyString Special variable value: % Regexp.last_match = #<MatchData "%"> ``` Maybe there is something off with with control frame when params are forwarded? Thanks in advance! -- https://bugs.ruby-lang.org/
2 1
0 0
[ruby-core:119514] [Ruby master Bug#20796] Segmentation fault in rubyzip tests with ruby 3.4.0-preview2
by tikkss (Tsutomu Katsube) 22 Oct '24

22 Oct '24
Issue #20796 has been reported by tikkss (Tsutomu Katsube). ---------------------------------------- Bug #20796: Segmentation fault in rubyzip tests with ruby 3.4.0-preview2 https://bugs.ruby-lang.org/issues/20796 * Author: tikkss (Tsutomu Katsube) * Status: Open * ruby -v: ruby 3.4.0preview2 (2024-10-07 master 32c733f57b) +PRISM [x86_64-darwin24] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- Steps to reproduce --- ```console $ git clone git@github.com:rubyzip/rubyzip $ cd rubyzip $ bundle $ bundle exec rake ``` Expected behavior --- The tests should complete successfully. Actual behavior --- A segmentation fault occurs during the test run. This issue does not occur with ruby 3.4.0-preview1 or other Ruby versions. Console dump --- See attached `crash.log` and `ruby-2024-10-13-071029.ips` for full details ```console $ bundle exec rake TESTOPTS="-v --seed=1" 2>crash.log Run options: -v --seed=1 # Running: ZipFileTest#test_get_output_stream = 0.02 s = . ZipFileTest#test_add_directory = 0.01 s = . ZipFileTest#test_streaming = 0.01 s = . ZipFileTest#test_nonexistant_zip = 0.00 s = . ZipFileTest#test_open_buffer_without_block = 0.00 s = . ZipFileTest#test_rename_to_existing_entry = 0.00 s = . ZipFileTest#test_open_buffer_with_io_and_block = 0.00 s = . ZipFileTest#test_write_buffer = 0.01 s = . ZipFileTest#test_open_buffer_with_stringio = 0.00 s = . ZipFileTest#test_odd_extra_field = 0.00 s = . ZipFileTest#test_add_existing_entry_name = 0.00 s = . ZipFileTest#test_open_buffer_no_op_does_not_change_file = 0.00 s = . ZipFileTest#test_replace = 0.01 s = . ZipFileTest#test_rename = 0.01 s = . ZipFileTest#test_recover_permissions_after_add_files_to_archive = % ``` My environment --- ```console $ gem env RubyGems Environment: - RUBYGEMS VERSION: 3.6.0.dev - RUBY VERSION: 3.4.0 (2024-10-07 patchlevel -1) [x86_64-darwin24] - INSTALLATION DIRECTORY: /Users/zzz/.rbenv/versions/3.4.0-preview2/lib/ruby/gems/3.4.0+0 - USER INSTALLATION DIRECTORY: /Users/zzz/.gem/ruby/3.4.0+0 - RUBY EXECUTABLE: /Users/zzz/.rbenv/versions/3.4.0-preview2/bin/ruby - GIT EXECUTABLE: /usr/local/bin/git - EXECUTABLE DIRECTORY: /Users/zzz/.rbenv/versions/3.4.0-preview2/bin - SPEC CACHE DIRECTORY: /Users/zzz/.gem/specs - SYSTEM CONFIGURATION DIRECTORY: /Users/zzz/.rbenv/versions/3.4.0-preview2/etc - RUBYGEMS PLATFORMS: - ruby - x86_64-darwin-24 - GEM PATHS: - /Users/zzz/.rbenv/versions/3.4.0-preview2/lib/ruby/gems/3.4.0+0 - /Users/zzz/.gem/ruby/3.4.0+0 - GEM CONFIGURATION: - :update_sources => true - :verbose => true - :backtrace => true - :bulk_threshold => 1000 - "gem" => "--no-document" - REMOTE SOURCES: - https://rubygems.org/ - SHELL PATH: - /Users/zzz/.rbenv/versions/3.4.0-preview2/bin - /usr/local/Cellar/rbenv/1.3.0/libexec - /Users/zzz/.local/bin - /Users/zzz/.rbenv/shims - /Users/zzz/.rbenv/bin - /Users/zzz/.nodenv/bin - /Users/zzz/bin - /Users/zzz/.cargo/bin - /usr/local/sbin - /usr/local/bin - /System/Cryptexes/App/usr/bin - /usr/bin - /bin - /usr/sbin - /sbin - /var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin - /var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin - /var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin - /Library/Apple/usr/bin ``` ```console $ cat Gemfile.lock PATH remote: . specs: rubyzip (3.0.0.alpha) GEM remote: https://rubygems.org/ specs: ast (2.4.2) docile (1.4.1) json (2.7.2) language_server-protocol (3.17.0.3) minitest (5.22.3) parallel (1.26.3) parser (3.3.5.0) ast (~> 2.4.1) racc psych (5.1.2) stringio racc (1.8.1) rainbow (3.1.1) rake (13.1.0) rdoc (6.6.3.1) psych (>= 4.0.0) regexp_parser (2.9.2) rexml (3.3.8) rubocop (1.61.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) rubocop-ast (>= 1.30.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.32.3) parser (>= 3.3.1.0) rubocop-performance (1.20.2) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.30.0, < 2.0) rubocop-rake (0.6.0) rubocop (~> 1.0) ruby-progressbar (1.13.0) simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.13.1) simplecov-lcov (0.8.0) simplecov_json_formatter (0.1.4) stringio (3.1.1) unicode-display_width (2.6.0) PLATFORMS ruby x86_64-darwin-24 DEPENDENCIES minitest (~> 5.22.0) rake (~> 13.1.0) rdoc (~> 6.6.2) rubocop (~> 1.61.0) rubocop-performance (~> 1.20.0) rubocop-rake (~> 0.6.0) rubyzip! simplecov (~> 0.22.0) simplecov-lcov (~> 0.8) BUNDLED WITH 2.6.0.dev ``` ---Files-------------------------------- crash.log (74.3 KB) ruby-2024-10-13-071029.ips (31.5 KB) -- https://bugs.ruby-lang.org/
4 9
0 0
[ruby-core:119592] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
by Dan0042 (Daniel DeLorme) 22 Oct '24

22 Oct '24
Issue #15381 has been updated by Dan0042 (Daniel DeLorme). > There are certainly backwards compatibility issues from changing `**` from calling `to_hash` to `to_h`. What kind of backwards compatibility issues exactly? My idea was to call #to_hash and fall back to #to_h, that should ensure no backwards incompatibility at all, unless I'm missing something? > Using the unary `**` operator on an object would call the `**@` method, which should return a hash (or raise an exception). That's a very intriguing solution, and very elegant I have to say. ---------------------------------------- Feature #15381: Let double splat call `to_h` implicitly https://bugs.ruby-lang.org/issues/15381#change-110213 * Author: sawa (Tsuyoshi Sawada) * Status: Open ---------------------------------------- The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal: ```ruby a = [ *(:foo if some_condition), *(:bar if another_condition), ] ``` And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol: ```ruby some_method(&:some_method_name) ``` Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows: ```ruby h = { **({a: 1} if some_condition), **({b: 2) if another_condition), } ``` There may be some other benefits of this feature that I have not noticed yet. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:119591] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
by jeremyevans0 (Jeremy Evans) 22 Oct '24

22 Oct '24
Issue #15381 has been updated by jeremyevans0 (Jeremy Evans). There are certainly backwards compatibility issues from changing `**` from calling `to_hash` to `to_h`. I'm sympathetic to the argument that calling `to_h` fits better, as the conversion is explicit and not implicit, but the backwards compatibility costs are probably too high. Maybe in Ruby 4? One possible approach is defining `**@` as an operator method, something like: ```ruby class BasicObject def **@ = to_hash end ``` Using the unary `**` operator on an object would call the `**@` method, which should return a hash (or raise an exception). The method name itself is designed to be similar to `+@` and `-@`, which are called when you use the unary `+` and `-` operators. Users could then change the `**@` method to call `to_h` instead of `to_hash` if they want, and get the explicit conversion behavior (either for all objects, or for specific objects/classes). I proposed `*@` as the method called by the unary `*` operator in #2013, with a working patch, before `**` was introduced for keywords. This was the first issue I filed, back in 2009. It was eventually rejected as there was not much discussion on it, but it was still thought an interesting idea at the time it was rejected. ---------------------------------------- Feature #15381: Let double splat call `to_h` implicitly https://bugs.ruby-lang.org/issues/15381#change-110212 * Author: sawa (Tsuyoshi Sawada) * Status: Open ---------------------------------------- The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal: ```ruby a = [ *(:foo if some_condition), *(:bar if another_condition), ] ``` And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol: ```ruby some_method(&:some_method_name) ``` Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows: ```ruby h = { **({a: 1} if some_condition), **({b: 2) if another_condition), } ``` There may be some other benefits of this feature that I have not noticed yet. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:119590] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
by Dan0042 (Daniel DeLorme) 22 Oct '24

22 Oct '24
Issue #15381 has been updated by Dan0042 (Daniel DeLorme). > I don’t think it can be treated as “explicitly” The `**` is right there in the code, written out caller-side, you can't get more "explicit" than that. > We can apply the same argument to `1 + obj` No we can't; as you know `+` is a method (I guess that would make `**` a "true" operator?) so `1.+(obj)` is similar to `{}.merge(obj)` and falls under implicit conversion (which the method is free to do or not) > What if it _is_ a typo/error? Then I'll fix my stupid mistakes by my own stupid self, thank you very much. > Now, if the user misuses it (by mistake or misunderstanding) and passes some, say, ActiveRecord model as a second parameter, then, with `to_h`, it would be successfully unpacked I think that would be awesome. If I do `other_method(**model)` and that `model` is representable as a hash, passing it as keyword arguments is beautiful. Imagine something like ```ruby ValidOptions = Struct.new(:ssl, :host, :port) opts = ValidOptions.new opts.port = 999 setup_request(**opts) ``` > * problem of things being _unintentionally_ unpacked, considering how many objects have `to_h` method That never happens. I have never ever written code where `foo(**opts)` throws "no implicit conversion of Object into Hash" and then I realize I really meant to use something other than `opts`. > (other than `**(params if condition?)`, which was actually handled). I'll admit that `**nil` covers 90% of the benefits, but the adhoc-ness of it all is a bit frustrating. ---------------------------------------- Feature #15381: Let double splat call `to_h` implicitly https://bugs.ruby-lang.org/issues/15381#change-110211 * Author: sawa (Tsuyoshi Sawada) * Status: Open ---------------------------------------- The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal: ```ruby a = [ *(:foo if some_condition), *(:bar if another_condition), ] ``` And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol: ```ruby some_method(&:some_method_name) ``` Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows: ```ruby h = { **({a: 1} if some_condition), **({b: 2) if another_condition), } ``` There may be some other benefits of this feature that I have not noticed yet. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:119589] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
by zverok (Victor Shepelev) 22 Oct '24

22 Oct '24
Issue #15381 has been updated by zverok (Victor Shepelev). > `{}.merge(**obj)` => obj is explicitly splatted but conversion is done via #to_hash instead of #to_h. It makes no sense, as many many people have commented through the years. I don’t think it can be treated as “explicitly” (invoking hash conversion); it is rather “we apply an operator, which would work with kind-of hash”. We can apply the same argument to `1 + obj`: “you see, I am _explicitly_ summing it with an integer; why is it not converted with `to_int`?” > `**obj` is my intent, not a typo. What if it _is_ a typo/error? Assume this API (frequent in many long-living codebases, which are partially old-style “options hash” and partially new-style “keyword arguments”): ```ruby def process(something, options = {}) # ... other_method(**options) end ``` Now, if the user misuses it (by mistake or misunderstanding) and passes some, say, ActiveRecord model as a second parameter, then, with `to_h`, it would be successfully unpacked, and might go this way (as “keyword arguments” which shouldn’t have been) through several more delegating methods before failing in completely different place—with an extremely hard to debug problem. So, what we are weighting here are: * convenience of unpacking non-hashes into keyword arguments (BTW, what exactly is the use case for this convenience?..), vs. * problem of things being _unintentionally_ unpacked, considering how many objects have `to_h` method; basically failing to “fail early” (where the mistake was made) and instead passing the mistake for who-know-which depth. I honestly fail to see the use case for `to_h` being used with `**` that outweighs the possible problems (other than `**(params if condition?)`, which was actually handled). ---------------------------------------- Feature #15381: Let double splat call `to_h` implicitly https://bugs.ruby-lang.org/issues/15381#change-110210 * Author: sawa (Tsuyoshi Sawada) * Status: Open ---------------------------------------- The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal: ```ruby a = [ *(:foo if some_condition), *(:bar if another_condition), ] ``` And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol: ```ruby some_method(&:some_method_name) ``` Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows: ```ruby h = { **({a: 1} if some_condition), **({b: 2) if another_condition), } ``` There may be some other benefits of this feature that I have not noticed yet. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:119588] [Ruby master Feature#15381] Let double splat call `to_h` implicitly
by Dan0042 (Daniel DeLorme) 22 Oct '24

22 Oct '24
Issue #15381 has been updated by Dan0042 (Daniel DeLorme). `to_{t}` methods are for explicit type conversion, and `to_{type}` methods are for implicit type conversion. `{}.merge(obj)` => obj is implicitly expected to be Hash, or converted via #to_hash `{}.merge(obj.to_h)` => obj is explicitly converted via #to_h `{}.merge(**obj)` => obj is **explicitly** splatted but conversion is done via #to_hash instead of #to_h. It makes no sense, as many many people have commented through the years. If you're double-splatting an object, of course you'd expect it to be convertible to a Hash. Please assume I'm not an idiot and that `**obj` is my intent, not a typo. Being overly restrictive (only true Hash-like objects can be used!) serves no purpose. Having to do `**obj.to_h` is silly, and adding #to_hash to a class in order to make it splattable is even more silly (possibly dangerous). The fix is easy and backward-compatible; just let double splat convert the object with both #to_hash and #to_h. But instead the "fix" that we got is a weird (although useful) one-off exception for `**nil`. 🙄 ---------------------------------------- Feature #15381: Let double splat call `to_h` implicitly https://bugs.ruby-lang.org/issues/15381#change-110209 * Author: sawa (Tsuyoshi Sawada) * Status: Open ---------------------------------------- The single splat calls `to_a` implicitly on the object (if it is not an array already) so that, for example, we have the convenience of writing conditions in an array literal: ```ruby a = [ *(:foo if some_condition), *(:bar if another_condition), ] ``` And the ampersand implicitly calls `to_proc` on the object (if it is not a proc already) so that we can substitute a block with an ampersand followed by a symbol: ```ruby some_method(&:some_method_name) ``` Unlike the single splat and ampersand, the double splat does not seem to implicitly call a corresponding method. I propose that the double splat should call `to_h` implicitly on the object if it not already a Hash so that we can, for example, write a condition in a hash literal as follows: ```ruby h = { **({a: 1} if some_condition), **({b: 2) if another_condition), } ``` There may be some other benefits of this feature that I have not noticed yet. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:119587] [Ruby master Bug#20809] Ripper fails to parse/tokenize nested heredocs within embexpr
by tompng (tomoya ishida) 22 Oct '24

22 Oct '24
Issue #20809 has been reported by tompng (tomoya ishida). ---------------------------------------- Bug #20809: Ripper fails to parse/tokenize nested heredocs within embexpr https://bugs.ruby-lang.org/issues/20809 * Author: tompng (tomoya ishida) * Status: Open * ruby -v: ruby 3.4.0dev (2024-10-22T09:04:30Z master 54065f3b7b) +PRISM [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- In this example, Ripper wrongly concats `"s333\n"` and `"s4444"`. ~~~ruby require 'ripper' code1 = '<<HEREDOC1 s1 #{<<HEREDOC2}s333 s22 HEREDOC2 s4444#{55555} HEREDOC1' p Ripper.tokenize(code1) # => ["<<HEREDOC1", "\n", "s1\n", "\#{", "<<HEREDOC2", "}", "s333\ns4444", "s22\n", "HEREDOC2\n", "\#{", "55555", "}", "\n", "HEREDOC1"] ~~~ In this example, result of `Ripper.sexp` is wrong. `"s333"` disappears. ~~~ruby code2 = '<<HEREDOC1 s1 #{<<HEREDOC2}s333 s22 HEREDOC2 s4444 HEREDOC1' p eval(code2) # => "s1\ns22\ns333\ns4444\n" p Ripper.sexp(code2) # => [:program, [[:string_literal, [:string_content, [:@tstring_content, "s1\n", [2, 0]], [:string_embexpr, [[:string_literal, [:string_content, [:@tstring_content, "s22\n", [4, 0]]]]]], [:@tstring_content, "s4444\n", [6, 0]]]]]] ~~~ -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:118932] [Ruby master Bug#20693] Dir.tmpdir should perform a real access check before warning about writability
by kjtsanaktsidis (KJ Tsanaktsidis) 22 Oct '24

22 Oct '24
Issue #20693 has been reported by kjtsanaktsidis (KJ Tsanaktsidis). ---------------------------------------- Bug #20693: Dir.tmpdir should perform a real access check before warning about writability https://bugs.ruby-lang.org/issues/20693 * Author: kjtsanaktsidis (KJ Tsanaktsidis) * Status: Open * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- The code in `Dir.tmpdir` attempts to warn the user if their temp directory is deficient for some reason: ```ruby case when !stat.directory? warn "#{name} is not a directory: #{dir}" when !stat.writable? warn "#{name} is not writable: #{dir}" when stat.world_writable? && !stat.sticky? warn "#{name} is world-writable: #{dir}" else break dir end ``` This check for writability is looking at the user/group/world access bits on the stat output, and determining if the user running Ruby is allowed to write to the temp directory based on that. However, modern operating systems contain other mechanisms apart from the user/group/world bits which can grant access to a directory that would otherwise be denied, or vice versa. Things like: * Posix ACL's * Linux's capabilities like CAP_DAC_OVERRIDE * Linux Security Modules like SELinux or AppArmor * Syscall filters like Linux's seccomp * Granular capability systems like FreeBSD's Capsicum * OpenBSD's pledge and unveil * Windows too has a rich ACL system for controlling filesystem access To address this, we should call `File.writable?` instead of `stat.writable?`, which asks the system whether the file is writable using the `euidaccess()` function if available. On Linux/glibc, at least, this will issue an `access(2)` syscall, and the Kernel can take all of the above into account. n.b. if Ruby is running as suid, then glibc currently will NOT ask the kernel to perform the access check in `euidaccess()`, and instead does a similar thing to what `Stat#writable?` does (https://github.com/bminor/glibc/blob/7f04bb4e49413bd57ac3215f3480b09ae71319…) This is because of the relatively new `faccessat2(2)` syscall is required to do this properly, and there is some ecosystem issues with leveraging this by default (e.g. https://bugzilla.redhat.com/show_bug.cgi?id=1900021) Since running Ruby as suid is probably a very bad idea anyway, and the glibc implementation isn't any worse than the `Stat#writable?` one, this seems OK though. -- https://bugs.ruby-lang.org/
4 8
0 0
  • ← Newer
  • 1
  • ...
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • ...
  • 21
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.