Skip to content

Commit c49ff9e

Browse files
committed
🐛 Use Range#size vs Range#count for uid-set limit
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).
1 parent 38ce681 commit c49ff9e

File tree

2 files changed

+8
-1
lines changed

2 files changed

+8
-1
lines changed

lib/net/imap/response_parser.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1382,7 +1382,7 @@ def uid_set
13821382
when T_NUMBER then [Integer(token.value)]
13831383
when T_ATOM
13841384
entries = uid_set__ranges(token.value)
1385-
if (count = entries.sum(&:count)) > MAX_UID_SET_SIZE
1385+
if (count = entries.sum(&:size)) > MAX_UID_SET_SIZE
13861386
parse_error("uid-set is too large: %d > 10k", count)
13871387
end
13881388
entries.flat_map(&:to_a)

test/net/imap/test_imap_response_parser.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,13 @@ def test_uidplus_copyuid__too_large
445445
"A004 OK [copyUID 1 10000:20000,1 1:10001] Done\r\n"
446446
)
447447
end
448+
Timeout.timeout(1) do
449+
assert_raise Net::IMAP::ResponseParseError, /uid-set is too large/ do
450+
parser.parse(
451+
"A004 OK [copyUID 1 1:#{2**32 - 1} 1:#{2**32 - 1}] Done\r\n"
452+
)
453+
end
454+
end
448455
end
449456

450457
end

0 commit comments

Comments
 (0)