mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	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
This commit is contained in:
		
							parent
							
								
									52f91c642b
								
							
						
					
					
						commit
						0b4ffb08cc
					
				
					 3 changed files with 23 additions and 2 deletions
				
			
		|  | @ -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: | ||||
|  |  | |||
|  | @ -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_' | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| fix negative numbers failing in verify() | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Ethan Furman
						Ethan Furman