]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-99248: [Enum] fix negative number infinite loop (GH-99256)
authorEthan Furman <ethan@stoneleaf.us>
Tue, 8 Nov 2022 20:00:19 +0000 (12:00 -0800)
committerGitHub <noreply@github.com>
Tue, 8 Nov 2022 20:00:19 +0000 (12:00 -0800)
[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

Lib/enum.py
Lib/test/test_enum.py
Misc/NEWS.d/next/Library/2022-11-08-11-15-37.gh-issue-99248.1vt8xI.rst [new file with mode: 0644]

index c1ccf53dc63942ac370ed53fc148c8e28599731b..f6c34ea06d2aff82abea7f63c6c366b988f4b366 100644 (file)
@@ -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:
index 03a9c610a86d4c9d035775643dbf2ad6eb14584e..9097a0936c0db7bb6a8583797f0b30eebff55014 100644 (file)
@@ -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_'
diff --git a/Misc/NEWS.d/next/Library/2022-11-08-11-15-37.gh-issue-99248.1vt8xI.rst b/Misc/NEWS.d/next/Library/2022-11-08-11-15-37.gh-issue-99248.1vt8xI.rst
new file mode 100644 (file)
index 0000000..99bf1d5
--- /dev/null
@@ -0,0 +1 @@
+fix negative numbers failing in verify()