summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorEthan Furman <ethan@stoneleaf.us>2022-11-08 20:00:19 (GMT)
committerGitHub <noreply@github.com>2022-11-08 20:00:19 (GMT)
commit0b4ffb08ccdc21fc07ce90d3f78b58a25e1af653 (patch)
treea8a7341c62dfd4a6c800f4ea411e762aa5604882 /Lib
parent52f91c642b72003c57fc1fb855beab6dfab155b7 (diff)
downloadcpython-0b4ffb08ccdc21fc07ce90d3f78b58a25e1af653.zip
cpython-0b4ffb08ccdc21fc07ce90d3f78b58a25e1af653.tar.gz
cpython-0b4ffb08ccdc21fc07ce90d3f78b58a25e1af653.tar.bz2
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
Diffstat (limited to 'Lib')
-rw-r--r--Lib/enum.py8
-rw-r--r--Lib/test/test_enum.py16
2 files changed, 22 insertions, 2 deletions
diff --git a/Lib/enum.py b/Lib/enum.py
index c1ccf53..f6c34ea 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -114,9 +114,12 @@ def _make_class_unpicklable(obj):
setattr(obj, '__module__', '<unknown>')
def _iter_bits_lsb(num):
- # num must be an integer
+ # num must be a positive integer
+ original = num
if isinstance(num, Enum):
num = num.value
+ if num < 0:
+ raise ValueError('%r is not a positive integer' % original)
while num:
b = num & (~num + 1)
yield b
@@ -1839,6 +1842,9 @@ class verify:
if name in member_names:
# not an alias
continue
+ if alias.value < 0:
+ # negative numbers are not checked
+ continue
values = list(_iter_bits_lsb(alias.value))
missed = [v for v in values if v not in member_values]
if missed:
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index 03a9c61..9097a09 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -14,7 +14,7 @@ from datetime import date
from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
-from enum import member, nonmember
+from enum import member, nonmember, _iter_bits_lsb
from io import StringIO
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
from test import support
@@ -174,6 +174,10 @@ class TestHelpers(unittest.TestCase):
for name in self.sunder_names + self.dunder_names + self.random_names:
self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
+ def test_iter_bits_lsb(self):
+ self.assertEqual(list(_iter_bits_lsb(7)), [1, 2, 4])
+ self.assertRaisesRegex(ValueError, '-8 is not a positive integer', list, _iter_bits_lsb(-8))
+
# for subclassing tests
@@ -3960,6 +3964,16 @@ class TestVerify(unittest.TestCase):
triple = 3
value = 4
+ def test_negative_alias(self):
+ @verify(NAMED_FLAGS)
+ class Color(Flag):
+ RED = 1
+ GREEN = 2
+ BLUE = 4
+ WHITE = -1
+ # no error means success
+
+
class TestInternals(unittest.TestCase):
sunder_names = '_bad_', '_good_', '_what_ho_'