Skip to content

Commit 6f4560d

Browse files
committed
🐛 SequenceSet#xor should not modify self
`set ^ other` and `set.xor other` are supposed to be safe transforms. But, unfortunately, they modified the receiver if it wasn't frozen, and crashed when it was! The fix is trivial: convert `self` to `dup`.
1 parent 4918584 commit 6f4560d

File tree

2 files changed

+4
-2
lines changed

2 files changed

+4
-2
lines changed

lib/net/imap/sequence_set.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ def &(other)
672672
#
673673
# <tt>(seqset ^ other)</tt> is equivalent to <tt>((seqset | other) -
674674
# (seqset & other))</tt>.
675-
def ^(other) remain_frozen (self | other).subtract(self & other) end
675+
def ^(other) remain_frozen (dup | other).subtract(self & other) end
676676
alias xor :^
677677

678678
# :call-seq:

test/net/imap/test_sequence_set.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,17 @@ def compare_to_reference_set(nums, set, seqset)
8989
data "#union", {transform: ->{ _1 | (1..100) }, }
9090
data "#intersection", {transform: ->{ _1 & (1..100) }, }
9191
data "#difference", {transform: ->{ _1 - (1..100) }, }
92-
# data "#xor", {transform: ->{ _1 ^ (1..100) }, }
92+
data "#xor", {transform: ->{ _1 ^ (1..100) }, }
9393
data "#complement", {transform: ->{ ~_1 }, }
9494
data "#normalize", {transform: ->{ _1.normalize }, }
9595
data "#limit", {transform: ->{ _1.limit(max: 22) }, freeze: :always }
9696
data "#limit => empty", {transform: ->{ _1.limit(max: 1) }, freeze: :always }
9797
test "transforms keep frozen status" do |data|
9898
data => {transform:}
9999
set = SequenceSet.new("2:4,7:11,99,999")
100+
dup = set.dup
100101
result = transform.to_proc.(set)
102+
assert_equal dup, set, "transform should not modified"
101103
if data in {freeze: :always}
102104
assert result.frozen?, "this transform always returns frozen"
103105
else

0 commit comments

Comments
 (0)