Skip to content

Commit

Permalink
🐛 Use Range#size vs Range#count for uid-set limit
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
nevans committed Feb 26, 2025
1 parent 38ce681 commit c49ff9e
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/net/imap/response_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions test/net/imap/test_imap_response_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit c49ff9e

Please sign in to comment.