Skip to content

Commit 4f31171

Browse files
gh-99248: [Enum] fix negative number infinite loop (GH-99256)
[Enum] fix negative number infinite loop - _iter_bits_lsb() now raises a ValueError if a negative number is passed in - verify() now skips checking negative numbers for named flags (cherry picked from commit 0b4ffb0) Co-authored-by: Ethan Furman <[email protected]>
1 parent ca94462 commit 4f31171

File tree

3 files changed

+23
-2
lines changed

3 files changed

+23
-2
lines changed

Lib/enum.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,12 @@ def _break_on_call_reduce(self, proto):
114114
setattr(obj, '__module__', '<unknown>')
115115

116116
def _iter_bits_lsb(num):
117-
# num must be an integer
117+
# num must be a positive integer
118+
original = num
118119
if isinstance(num, Enum):
119120
num = num.value
121+
if num < 0:
122+
raise ValueError('%r is not a positive integer' % original)
120123
while num:
121124
b = num & (~num + 1)
122125
yield b
@@ -1856,6 +1859,9 @@ def __call__(self, enumeration):
18561859
if name in member_names:
18571860
# not an alias
18581861
continue
1862+
if alias.value < 0:
1863+
# negative numbers are not checked
1864+
continue
18591865
values = list(_iter_bits_lsb(alias.value))
18601866
missed = [v for v in values if v not in member_values]
18611867
if missed:

Lib/test/test_enum.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
1515
from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
1616
from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
17-
from enum import member, nonmember
17+
from enum import member, nonmember, _iter_bits_lsb
1818
from io import StringIO
1919
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
2020
from test import support
@@ -174,6 +174,10 @@ def test_is_private(self):
174174
for name in self.sunder_names + self.dunder_names + self.random_names:
175175
self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
176176

177+
def test_iter_bits_lsb(self):
178+
self.assertEqual(list(_iter_bits_lsb(7)), [1, 2, 4])
179+
self.assertRaisesRegex(ValueError, '-8 is not a positive integer', list, _iter_bits_lsb(-8))
180+
177181

178182
# for subclassing tests
179183

@@ -3965,6 +3969,16 @@ class Sillier(IntEnum):
39653969
triple = 3
39663970
value = 4
39673971

3972+
def test_negative_alias(self):
3973+
@verify(NAMED_FLAGS)
3974+
class Color(Flag):
3975+
RED = 1
3976+
GREEN = 2
3977+
BLUE = 4
3978+
WHITE = -1
3979+
# no error means success
3980+
3981+
39683982
class TestInternals(unittest.TestCase):
39693983

39703984
sunder_names = '_bad_', '_good_', '_what_ho_'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fix negative numbers failing in verify()

0 commit comments

Comments
 (0)