mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-130139: always check ast node type in ast.parse() with ast input (#130140)
This commit is contained in:
parent
2e8044a4f7
commit
c9b1bf302c
8 changed files with 73 additions and 32 deletions
|
@ -346,6 +346,10 @@ ast
|
|||
* The ``repr()`` output for AST nodes now includes more information.
|
||||
(Contributed by Tomas R in :gh:`116022`.)
|
||||
|
||||
* :func:`ast.parse`, when called with an AST as input, now always verifies
|
||||
that the root node type is appropriate.
|
||||
(Contributed by Irit Katriel in :gh:`130139`.)
|
||||
|
||||
|
||||
calendar
|
||||
--------
|
||||
|
|
1
Include/internal/pycore_ast.h
generated
1
Include/internal/pycore_ast.h
generated
|
@ -907,6 +907,7 @@ type_param_ty _PyAST_TypeVarTuple(identifier name, expr_ty default_value, int
|
|||
|
||||
|
||||
PyObject* PyAST_mod2obj(mod_ty t);
|
||||
int PyAst_CheckMode(PyObject *ast, int mode);
|
||||
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);
|
||||
int PyAST_Check(PyObject* obj);
|
||||
|
||||
|
|
|
@ -131,6 +131,12 @@ class AST_Tests(unittest.TestCase):
|
|||
tree = ast.parse(snippet)
|
||||
compile(tree, '<string>', 'exec')
|
||||
|
||||
def test_parse_invalid_ast(self):
|
||||
# see gh-130139
|
||||
for optval in (-1, 0, 1, 2):
|
||||
self.assertRaises(TypeError, ast.parse, ast.Constant(42),
|
||||
optimize=optval)
|
||||
|
||||
def test_optimization_levels__debug__(self):
|
||||
cases = [(-1, '__debug__'), (0, '__debug__'), (1, False), (2, False)]
|
||||
for (optval, expected) in cases:
|
||||
|
|
|
@ -422,9 +422,9 @@ class UnparseTestCase(ASTTestCase):
|
|||
self.check_ast_roundtrip(f"'''{docstring}'''")
|
||||
|
||||
def test_constant_tuples(self):
|
||||
self.check_src_roundtrip(ast.Constant(value=(1,), kind=None), "(1,)")
|
||||
self.check_src_roundtrip(ast.Module([ast.Constant(value=(1,))]), "(1,)")
|
||||
self.check_src_roundtrip(
|
||||
ast.Constant(value=(1, 2, 3), kind=None), "(1, 2, 3)"
|
||||
ast.Module([ast.Constant(value=(1, 2, 3))]), "(1, 2, 3)"
|
||||
)
|
||||
|
||||
def test_function_type(self):
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Fix bug where :func:`ast.parse` did not error on AST input which is not of the
|
||||
correct type, when called with optimize=False.
|
|
@ -2166,11 +2166,35 @@ PyObject* PyAST_mod2obj(mod_ty t)
|
|||
}
|
||||
|
||||
/* mode is 0 for "exec", 1 for "eval" and 2 for "single" input */
|
||||
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
|
||||
int PyAst_CheckMode(PyObject *ast, int mode)
|
||||
{
|
||||
const char * const req_name[] = {"Module", "Expression", "Interactive"};
|
||||
int isinstance;
|
||||
|
||||
struct ast_state *state = get_ast_state();
|
||||
if (state == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyObject *req_type[3];
|
||||
req_type[0] = state->Module_type;
|
||||
req_type[1] = state->Expression_type;
|
||||
req_type[2] = state->Interactive_type;
|
||||
|
||||
assert(0 <= mode && mode <= 2);
|
||||
int isinstance = PyObject_IsInstance(ast, req_type[mode]);
|
||||
if (isinstance == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (!isinstance) {
|
||||
PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s",
|
||||
req_name[mode], _PyType_Name(Py_TYPE(ast)));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
|
||||
{
|
||||
if (PySys_Audit("compile", "OO", ast, Py_None) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2180,19 +2204,7 @@ mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *req_type[3];
|
||||
req_type[0] = state->Module_type;
|
||||
req_type[1] = state->Expression_type;
|
||||
req_type[2] = state->Interactive_type;
|
||||
|
||||
assert(0 <= mode && mode <= 2);
|
||||
|
||||
isinstance = PyObject_IsInstance(ast, req_type[mode]);
|
||||
if (isinstance == -1)
|
||||
return NULL;
|
||||
if (!isinstance) {
|
||||
PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s",
|
||||
req_name[mode], _PyType_Name(Py_TYPE(ast)));
|
||||
if (PyAst_CheckMode(ast, mode) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2356,6 +2368,7 @@ def write_header(mod, metadata, f):
|
|||
f.write(textwrap.dedent("""
|
||||
|
||||
PyObject* PyAST_mod2obj(mod_ty t);
|
||||
int PyAst_CheckMode(PyObject *ast, int mode);
|
||||
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);
|
||||
int PyAST_Check(PyObject* obj);
|
||||
|
||||
|
|
42
Python/Python-ast.c
generated
42
Python/Python-ast.c
generated
|
@ -18161,11 +18161,35 @@ PyObject* PyAST_mod2obj(mod_ty t)
|
|||
}
|
||||
|
||||
/* mode is 0 for "exec", 1 for "eval" and 2 for "single" input */
|
||||
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
|
||||
int PyAst_CheckMode(PyObject *ast, int mode)
|
||||
{
|
||||
const char * const req_name[] = {"Module", "Expression", "Interactive"};
|
||||
int isinstance;
|
||||
|
||||
struct ast_state *state = get_ast_state();
|
||||
if (state == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyObject *req_type[3];
|
||||
req_type[0] = state->Module_type;
|
||||
req_type[1] = state->Expression_type;
|
||||
req_type[2] = state->Interactive_type;
|
||||
|
||||
assert(0 <= mode && mode <= 2);
|
||||
int isinstance = PyObject_IsInstance(ast, req_type[mode]);
|
||||
if (isinstance == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (!isinstance) {
|
||||
PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s",
|
||||
req_name[mode], _PyType_Name(Py_TYPE(ast)));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
|
||||
{
|
||||
if (PySys_Audit("compile", "OO", ast, Py_None) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -18175,19 +18199,7 @@ mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *req_type[3];
|
||||
req_type[0] = state->Module_type;
|
||||
req_type[1] = state->Expression_type;
|
||||
req_type[2] = state->Interactive_type;
|
||||
|
||||
assert(0 <= mode && mode <= 2);
|
||||
|
||||
isinstance = PyObject_IsInstance(ast, req_type[mode]);
|
||||
if (isinstance == -1)
|
||||
return NULL;
|
||||
if (!isinstance) {
|
||||
PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s",
|
||||
req_name[mode], _PyType_Name(Py_TYPE(ast)));
|
||||
if (PyAst_CheckMode(ast, mode) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -835,6 +835,9 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
|
|||
goto error;
|
||||
if (is_ast) {
|
||||
if ((flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST) {
|
||||
if (PyAst_CheckMode(source, compile_mode) < 0) {
|
||||
goto error;
|
||||
}
|
||||
// return an un-optimized AST
|
||||
result = Py_NewRef(source);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue