gh-141778: add missing validation in ast.literal_eval() for non-string input

This also changes parsing of the private `__text_signature__` attribute
by inspect.signature().  Now we accept here only types, valid for
ast.Constant().
This commit is contained in:
Sergey B Kirpichev 2025-12-19 07:09:11 +03:00
parent 1391ee664c
commit 7c90e20a2c
5 changed files with 22 additions and 4 deletions

View file

@ -59,17 +59,26 @@ def literal_eval(node_or_string):
"""
if isinstance(node_or_string, str):
node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval').body
return _convert_literal(node_or_string, True)
elif isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
return _convert_literal(node_or_string)
def _convert_literal(node):
_type_None = type(None)
_type_Ellipsis = type(...)
def _convert_literal(node, omit_validation=False):
"""
Used by `literal_eval` to convert an AST node into a value.
"""
if isinstance(node, Constant):
return node.value
if omit_validation:
return node.value
if type(value := node.value) in (str, bytes, int, float, complex,
bool, _type_None, _type_Ellipsis):
return value
if isinstance(node, Dict) and len(node.keys) == len(node.values):
return dict(zip(
map(_convert_literal, node.keys),

View file

@ -2216,7 +2216,8 @@ def _signature_fromstr(cls, obj, s, skip_bound_arg=True):
except NameError:
raise ValueError
if isinstance(value, (str, int, float, bytes, bool, type(None))):
if type(value) in (str, int, float, bytes, bool, complex,
type(None), type(...)):
return ast.Constant(value)
raise ValueError

View file

@ -1890,6 +1890,10 @@ Module(
self.assertRaises(ValueError, ast.literal_eval, '++6')
self.assertRaises(ValueError, ast.literal_eval, '+True')
self.assertRaises(ValueError, ast.literal_eval, '2+3')
# gh-141778: reject values of invalid types
node = ast.Expression(body=ast.Constant(object()))
ast.fix_missing_locations(node)
self.assertRaises(ValueError, ast.literal_eval, node)
def test_literal_eval_str_int_limit(self):
with support.adjust_int_max_str_digits(4000):

View file

@ -6286,7 +6286,9 @@ class TestSignatureDefinitions(unittest.TestCase):
def test_thread_module_has_signatures(self):
import _thread
no_signature = {'RLock'}
self._test_module_has_signatures(_thread, no_signature)
unsupported_signature = {'interrupt_main'}
self._test_module_has_signatures(_thread, no_signature,
unsupported_signature)
def test_time_module_has_signatures(self):
no_signature = {

View file

@ -0,0 +1,2 @@
Validate value types of :class:`ast.Constant` nodes in the
:func:`ast.literal_eval`. Patch by Sergey B Kirpichev.