mirror of
https://github.com/python/cpython.git
synced 2025-10-09 16:34:44 +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.
|
* The ``repr()`` output for AST nodes now includes more information.
|
||||||
(Contributed by Tomas R in :gh:`116022`.)
|
(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
|
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);
|
PyObject* PyAST_mod2obj(mod_ty t);
|
||||||
|
int PyAst_CheckMode(PyObject *ast, int mode);
|
||||||
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);
|
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);
|
||||||
int PyAST_Check(PyObject* obj);
|
int PyAST_Check(PyObject* obj);
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,12 @@ class AST_Tests(unittest.TestCase):
|
||||||
tree = ast.parse(snippet)
|
tree = ast.parse(snippet)
|
||||||
compile(tree, '<string>', 'exec')
|
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):
|
def test_optimization_levels__debug__(self):
|
||||||
cases = [(-1, '__debug__'), (0, '__debug__'), (1, False), (2, False)]
|
cases = [(-1, '__debug__'), (0, '__debug__'), (1, False), (2, False)]
|
||||||
for (optval, expected) in cases:
|
for (optval, expected) in cases:
|
||||||
|
|
|
@ -422,9 +422,9 @@ class UnparseTestCase(ASTTestCase):
|
||||||
self.check_ast_roundtrip(f"'''{docstring}'''")
|
self.check_ast_roundtrip(f"'''{docstring}'''")
|
||||||
|
|
||||||
def test_constant_tuples(self):
|
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(
|
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):
|
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 */
|
/* 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"};
|
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) {
|
if (PySys_Audit("compile", "OO", ast, Py_None) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2180,19 +2204,7 @@ mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *req_type[3];
|
if (PyAst_CheckMode(ast, mode) < 0) {
|
||||||
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)));
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2356,6 +2368,7 @@ def write_header(mod, metadata, f):
|
||||||
f.write(textwrap.dedent("""
|
f.write(textwrap.dedent("""
|
||||||
|
|
||||||
PyObject* PyAST_mod2obj(mod_ty t);
|
PyObject* PyAST_mod2obj(mod_ty t);
|
||||||
|
int PyAst_CheckMode(PyObject *ast, int mode);
|
||||||
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);
|
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);
|
||||||
int PyAST_Check(PyObject* obj);
|
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 */
|
/* 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"};
|
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) {
|
if (PySys_Audit("compile", "OO", ast, Py_None) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -18175,19 +18199,7 @@ mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *req_type[3];
|
if (PyAst_CheckMode(ast, mode) < 0) {
|
||||||
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)));
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -835,6 +835,9 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
|
||||||
goto error;
|
goto error;
|
||||||
if (is_ast) {
|
if (is_ast) {
|
||||||
if ((flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST) {
|
if ((flags & PyCF_OPTIMIZED_AST) == PyCF_ONLY_AST) {
|
||||||
|
if (PyAst_CheckMode(source, compile_mode) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
// return an un-optimized AST
|
// return an un-optimized AST
|
||||||
result = Py_NewRef(source);
|
result = Py_NewRef(source);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue