From bed76ff14e181170ba623fbdd4ede7c9263bc9fa Mon Sep 17 00:00:00 2001 From: nick evans Date: Wed, 26 Feb 2025 15:10:09 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Use=20Range#size=20vs=20Range#co?= =?UTF-8?q?unt=20for=20uid-set=20limit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to ruby 3.3, `Range#count` is handled by `Enumerable#count`, even for numeric ranges. For large ranges, `Range#size` is _significantly_ faster. On my system, ruby 3.2 took 54 seconds (at 100% CPU) to run `(1...2**32).count`. Thanks to @xiaoge1001 for reporting this issue (#410). --- lib/net/imap/response_parser.rb | 2 +- test/net/imap/test_imap_response_parser.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/net/imap/response_parser.rb b/lib/net/imap/response_parser.rb index 0341356c7..5317bfc96 100644 --- a/lib/net/imap/response_parser.rb +++ b/lib/net/imap/response_parser.rb @@ -1382,7 +1382,7 @@ def uid_set when T_NUMBER then [Integer(token.value)] when T_ATOM entries = uid_set__ranges(token.value) - if (count = entries.sum(&:count)) > MAX_UID_SET_SIZE + if (count = entries.sum(&:size)) > MAX_UID_SET_SIZE parse_error("uid-set is too large: %d > 10k", count) end entries.flat_map(&:to_a) diff --git a/test/net/imap/test_imap_response_parser.rb b/test/net/imap/test_imap_response_parser.rb index 66df868c0..f1c48d8d4 100644 --- a/test/net/imap/test_imap_response_parser.rb +++ b/test/net/imap/test_imap_response_parser.rb @@ -445,6 +445,13 @@ def test_uidplus_copyuid__too_large "A004 OK [copyUID 1 10000:20000,1 1:10001] Done\r\n" ) end + Timeout.timeout(1) do + assert_raise Net::IMAP::ResponseParseError, /uid-set is too large/ do + parser.parse( + "A004 OK [copyUID 1 1:#{2**32 - 1} 1:#{2**32 - 1}] Done\r\n" + ) + end + end end end