[ruby-core:122773] [Ruby Feature#21513] Raise on converting endless range to set

Issue #21513 has been reported by viralpraxis (Iaroslav Kurbatov). ---------------------------------------- Feature #21513: Raise on converting endless range to set https://bugs.ruby-lang.org/issues/21513 * Author: viralpraxis (Iaroslav Kurbatov) * Status: Open ---------------------------------------- Converting endless range to array raises: ``` shell ruby -e '(1..).to_a' -e:1:in 'Range#to_a': cannot convert endless range to an array (RangeError) from -e:1:in '<main>' ``` but converting to set does not: ``` shell ruby -e '(1..).to_set # hangs' ``` I think it makes to raise in both cases for consistency. Something like this should do the trick: ``` diff diff --git i/prelude.rb w/prelude.rb index f49cada637..11bfa3fc95 100644 --- i/prelude.rb +++ w/prelude.rb @@ -30,6 +30,10 @@ module Enumerable # Makes a set from the enumerable object with given arguments. # Passing arguments to this method is deprecated. def to_set(*args, &block) + if self.class == Range && self.end.nil? + raise RangeError, "cannot convert endless range to a set" + end + klass = if args.empty? Set else diff --git i/test/ruby/test_range.rb w/test/ruby/test_range.rb index f875c0ab40..27b968641b 100644 --- i/test/ruby/test_range.rb +++ w/test/ruby/test_range.rb @@ -1541,4 +1541,11 @@ def test_overlap? assert_not_operator((1...3), :overlap?, (3..4)) assert_not_operator((...3), :overlap?, (3..)) end + + def test_to_set + assert_equal(Set[], (1..-1).to_set) + assert_equal(Set[1, 2, 3], (1..3).to_set) + + assert_raise(RangeError) { (239..).to_set } + end end ``` If this patch is accepted, I'll open a PR. ``` shell ./ruby -v ruby 3.5.0dev (2025-07-14T20:34:32Z master a6d483971a) +PRISM [x86_64-linux] ``` -- https://bugs.ruby-lang.org/

Issue #21513 has been updated by Dan0042 (Daniel DeLorme). Raising an error should be the case for ANY endless range operations that result in an infinite loop and memory consumption. This is a very costly and hard to debug failure mode, and it happens for a large number of endless range methods. ---------------------------------------- Feature #21513: Raise on converting endless range to set https://bugs.ruby-lang.org/issues/21513#change-114052 * Author: viralpraxis (Iaroslav Kurbatov) * Status: Open ---------------------------------------- Converting endless range to array raises: ``` shell ruby -e '(1..).to_a' -e:1:in 'Range#to_a': cannot convert endless range to an array (RangeError) from -e:1:in '<main>' ``` but converting to set does not: ``` shell ruby -e '(1..).to_set # hangs' ``` I think it makes to raise in both cases for consistency. Something like this should do the trick: ``` diff diff --git i/prelude.rb w/prelude.rb index f49cada637..11bfa3fc95 100644 --- i/prelude.rb +++ w/prelude.rb @@ -30,6 +30,10 @@ module Enumerable # Makes a set from the enumerable object with given arguments. # Passing arguments to this method is deprecated. def to_set(*args, &block) + if self.class == Range && self.end.nil? + raise RangeError, "cannot convert endless range to a set" + end + klass = if args.empty? Set else diff --git i/test/ruby/test_range.rb w/test/ruby/test_range.rb index f875c0ab40..27b968641b 100644 --- i/test/ruby/test_range.rb +++ w/test/ruby/test_range.rb @@ -1541,4 +1541,11 @@ def test_overlap? assert_not_operator((1...3), :overlap?, (3..4)) assert_not_operator((...3), :overlap?, (3..)) end + + def test_to_set + assert_equal(Set[], (1..-1).to_set) + assert_equal(Set[1, 2, 3], (1..3).to_set) + + assert_raise(RangeError) { (239..).to_set } + end end ``` If this patch is accepted, I'll open a PR. ``` shell ./ruby -v ruby 3.5.0dev (2025-07-14T20:34:32Z master a6d483971a) +PRISM [x86_64-linux] ``` -- https://bugs.ruby-lang.org/

Issue #21513 has been updated by nobu (Nobuyoshi Nakada). Thank you, good catch. I think that check should be in `Range#to_set`, as well as `Range#to_a`. ```ruby class Range # Makes a set from the range with given arguments, if a finite # collection; raises an exception otherwise. # Passing arguments to this method is deprecated. def to_set(...) if self.end.nil? raise RangeError, "cannot convert endless range to a set" end super end end ``` ---------------------------------------- Feature #21513: Raise on converting endless range to set https://bugs.ruby-lang.org/issues/21513#change-114058 * Author: viralpraxis (Iaroslav Kurbatov) * Status: Open ---------------------------------------- Converting endless range to array raises: ``` shell ruby -e '(1..).to_a' -e:1:in 'Range#to_a': cannot convert endless range to an array (RangeError) from -e:1:in '<main>' ``` but converting to set does not: ``` shell ruby -e '(1..).to_set # hangs' ``` I think it makes to raise in both cases for consistency. Something like this should do the trick: ``` diff diff --git i/prelude.rb w/prelude.rb index f49cada637..11bfa3fc95 100644 --- i/prelude.rb +++ w/prelude.rb @@ -30,6 +30,10 @@ module Enumerable # Makes a set from the enumerable object with given arguments. # Passing arguments to this method is deprecated. def to_set(*args, &block) + if self.class == Range && self.end.nil? + raise RangeError, "cannot convert endless range to a set" + end + klass = if args.empty? Set else diff --git i/test/ruby/test_range.rb w/test/ruby/test_range.rb index f875c0ab40..27b968641b 100644 --- i/test/ruby/test_range.rb +++ w/test/ruby/test_range.rb @@ -1541,4 +1541,11 @@ def test_overlap? assert_not_operator((1...3), :overlap?, (3..4)) assert_not_operator((...3), :overlap?, (3..)) end + + def test_to_set + assert_equal(Set[], (1..-1).to_set) + assert_equal(Set[1, 2, 3], (1..3).to_set) + + assert_raise(RangeError) { (239..).to_set } + end end ``` If this patch is accepted, I'll open a PR. ``` shell ./ruby -v ruby 3.5.0dev (2025-07-14T20:34:32Z master a6d483971a) +PRISM [x86_64-linux] ``` -- https://bugs.ruby-lang.org/

Issue #21513 has been updated by viralpraxis (Iaroslav Kurbatov). I've opened https://github.com/ruby/ruby/pull/13902 ---------------------------------------- Feature #21513: Raise on converting endless range to set https://bugs.ruby-lang.org/issues/21513#change-114065 * Author: viralpraxis (Iaroslav Kurbatov) * Status: Open ---------------------------------------- Converting endless range to array raises: ``` shell ruby -e '(1..).to_a' -e:1:in 'Range#to_a': cannot convert endless range to an array (RangeError) from -e:1:in '<main>' ``` but converting to set does not: ``` shell ruby -e '(1..).to_set # hangs' ``` I think it makes to raise in both cases for consistency. Something like this should do the trick: ``` diff diff --git i/prelude.rb w/prelude.rb index f49cada637..11bfa3fc95 100644 --- i/prelude.rb +++ w/prelude.rb @@ -30,6 +30,10 @@ module Enumerable # Makes a set from the enumerable object with given arguments. # Passing arguments to this method is deprecated. def to_set(*args, &block) + if self.class == Range && self.end.nil? + raise RangeError, "cannot convert endless range to a set" + end + klass = if args.empty? Set else diff --git i/test/ruby/test_range.rb w/test/ruby/test_range.rb index f875c0ab40..27b968641b 100644 --- i/test/ruby/test_range.rb +++ w/test/ruby/test_range.rb @@ -1541,4 +1541,11 @@ def test_overlap? assert_not_operator((1...3), :overlap?, (3..4)) assert_not_operator((...3), :overlap?, (3..)) end + + def test_to_set + assert_equal(Set[], (1..-1).to_set) + assert_equal(Set[1, 2, 3], (1..3).to_set) + + assert_raise(RangeError) { (239..).to_set } + end end ``` If this patch is accepted, I'll open a PR. ``` shell ./ruby -v ruby 3.5.0dev (2025-07-14T20:34:32Z master a6d483971a) +PRISM [x86_64-linux] ``` -- https://bugs.ruby-lang.org/

Issue #21513 has been updated by nobu (Nobuyoshi Nakada). I suspect this is a bug fix instead of a new feature, isn't it? ---------------------------------------- Feature #21513: Raise on converting endless range to set https://bugs.ruby-lang.org/issues/21513#change-114066 * Author: viralpraxis (Iaroslav Kurbatov) * Status: Open ---------------------------------------- Converting endless range to array raises: ``` shell ruby -e '(1..).to_a' -e:1:in 'Range#to_a': cannot convert endless range to an array (RangeError) from -e:1:in '<main>' ``` but converting to set does not: ``` shell ruby -e '(1..).to_set # hangs' ``` I think it makes to raise in both cases for consistency. Something like this should do the trick: ``` diff diff --git i/prelude.rb w/prelude.rb index f49cada637..11bfa3fc95 100644 --- i/prelude.rb +++ w/prelude.rb @@ -30,6 +30,10 @@ module Enumerable # Makes a set from the enumerable object with given arguments. # Passing arguments to this method is deprecated. def to_set(*args, &block) + if self.class == Range && self.end.nil? + raise RangeError, "cannot convert endless range to a set" + end + klass = if args.empty? Set else diff --git i/test/ruby/test_range.rb w/test/ruby/test_range.rb index f875c0ab40..27b968641b 100644 --- i/test/ruby/test_range.rb +++ w/test/ruby/test_range.rb @@ -1541,4 +1541,11 @@ def test_overlap? assert_not_operator((1...3), :overlap?, (3..4)) assert_not_operator((...3), :overlap?, (3..)) end + + def test_to_set + assert_equal(Set[], (1..-1).to_set) + assert_equal(Set[1, 2, 3], (1..3).to_set) + + assert_raise(RangeError) { (239..).to_set } + end end ``` If this patch is accepted, I'll open a PR. ``` shell ./ruby -v ruby 3.5.0dev (2025-07-14T20:34:32Z master a6d483971a) +PRISM [x86_64-linux] ``` -- https://bugs.ruby-lang.org/

Issue #21513 has been updated by Dan0042 (Daniel DeLorme). What's your opinion on adding the same raise/check for the following methods? They present the same infinite loop problem. #count #all? #collect / #map #collect_concat / #flat_map #compact #drop #drop_while #filter #filter_map #find_all / #select #grep #grep_v #group_by #inject / #reduce #max_by / #min_by / #minmax_by #none? #one? #partition #sort / #sort_by #sum #tally #to_h #uniq ---------------------------------------- Bug #21513: Converting endless range to set hangs https://bugs.ruby-lang.org/issues/21513#change-114069 * Author: viralpraxis (Iaroslav Kurbatov) * Status: Open * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Converting endless range to array raises: ``` shell ruby -e '(1..).to_a' -e:1:in 'Range#to_a': cannot convert endless range to an array (RangeError) from -e:1:in '<main>' ``` but converting to set does not: ``` shell ruby -e '(1..).to_set # hangs' ``` I think it makes to raise in both cases for consistency. Something like this should do the trick: ``` diff diff --git i/prelude.rb w/prelude.rb index f49cada637..11bfa3fc95 100644 --- i/prelude.rb +++ w/prelude.rb @@ -30,6 +30,10 @@ module Enumerable # Makes a set from the enumerable object with given arguments. # Passing arguments to this method is deprecated. def to_set(*args, &block) + if self.class == Range && self.end.nil? + raise RangeError, "cannot convert endless range to a set" + end + klass = if args.empty? Set else diff --git i/test/ruby/test_range.rb w/test/ruby/test_range.rb index f875c0ab40..27b968641b 100644 --- i/test/ruby/test_range.rb +++ w/test/ruby/test_range.rb @@ -1541,4 +1541,11 @@ def test_overlap? assert_not_operator((1...3), :overlap?, (3..4)) assert_not_operator((...3), :overlap?, (3..)) end + + def test_to_set + assert_equal(Set[], (1..-1).to_set) + assert_equal(Set[1, 2, 3], (1..3).to_set) + + assert_raise(RangeError) { (239..).to_set } + end end ``` If this patch is accepted, I'll open a PR. ``` shell ./ruby -v ruby 3.5.0dev (2025-07-14T20:34:32Z master a6d483971a) +PRISM [x86_64-linux] ``` -- https://bugs.ruby-lang.org/
participants (3)
-
Dan0042 (Daniel DeLorme)
-
nobu (Nobuyoshi Nakada)
-
viralpraxis (Iaroslav Kurbatov)