]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-99248: [Enum] fix negative number infinite loop (GH-99256)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 8 Nov 2022 20:33:21 +0000 (12:33 -0800)
committerGitHub <noreply@github.com>
Tue, 8 Nov 2022 20:33:21 +0000 (12:33 -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
(cherry picked from commit 0b4ffb08ccdc21fc07ce90d3f78b58a25e1af653)

Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
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 ec3ebde2868678a38177b71479434f88fbbb1fb1..62d6e25cecce0f5b08bc2675d622b5f4a2a62fc9 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
@@ -1856,6 +1859,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 d2b3a918d3ae0142dce12a8fdcd027b1bc58d494..a9b80ad0d3dbc3dcfe6c82a0a4b30566a4a41dee 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
 
@@ -3965,6 +3969,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()