[Python-checkins] gh-99248: [Enum] fix negative number infinite loop (GH-99256)

ethanfurman webhook-mailer at python.org
Tue Nov 8 15:00:26 EST 2022


https://github.com/python/cpython/commit/0b4ffb08ccdc21fc07ce90d3f78b58a25e1af653
commit: 0b4ffb08ccdc21fc07ce90d3f78b58a25e1af653
branch: main
author: Ethan Furman <ethan at stoneleaf.us>
committer: ethanfurman <ethan at stoneleaf.us>
date: 2022-11-08T12:00:19-08:00
summary:

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

files:
A Misc/NEWS.d/next/Library/2022-11-08-11-15-37.gh-issue-99248.1vt8xI.rst
M Lib/enum.py
M Lib/test/test_enum.py

diff --git a/Lib/enum.py b/Lib/enum.py
index c1ccf53dc639..f6c34ea06d2a 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -114,9 +114,12 @@ def _break_on_call_reduce(self, proto):
         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 @@ def __call__(self, enumeration):
                     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 03a9c610a86d..9097a0936c0d 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -14,7 +14,7 @@
 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 @@ def test_is_private(self):
         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 Sillier(IntEnum):
             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
index 000000000000..99bf1d5d08ba
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-11-08-11-15-37.gh-issue-99248.1vt8xI.rst
@@ -0,0 +1 @@
+fix negative numbers failing in verify()



More information about the Python-checkins mailing list