py/compile: Disallow 'import *' outside module level.

This check follows CPython's behaviour, because 'import *' always populates
the globals with the imported names, not locals.

Since it's safe to do this (doesn't lead to a crash or undefined behaviour)
the check is only enabled for MICROPY_CPYTHON_COMPAT.

Fixes issue #5121.
This commit is contained in:
Petr Viktorin 2019-09-20 09:16:34 +02:00 committed by Damien George
parent 26e90a0514
commit 25a9bccdee
4 changed files with 30 additions and 7 deletions

View File

@ -1196,6 +1196,13 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
} while (0); } while (0);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) { if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
#if MICROPY_CPYTHON_COMPAT
if (comp->scope_cur->kind != SCOPE_MODULE) {
compile_syntax_error(comp, (mp_parse_node_t)pns, "import * not at module level");
return;
}
#endif
EMIT_ARG(load_const_small_int, import_level); EMIT_ARG(load_const_small_int, import_level);
// build the "fromlist" tuple // build the "fromlist" tuple

View File

@ -115,7 +115,7 @@ def f():
# import # import
import a import a
from a import b from a import b
from a import * #from sys import * # tested at module scope
# raise # raise
raise raise
@ -154,3 +154,6 @@ del Class
# load super method # load super method
def f(self): def f(self):
super().f() super().f()
# import * (needs to be in module scope)
from sys import *

View File

@ -7,7 +7,7 @@ arg names:
(N_EXC_STACK 0) (N_EXC_STACK 0)
bc=0 line=1 bc=0 line=1
######## ########
bc=\\d\+ line=155 bc=\\d\+ line=159
00 MAKE_FUNCTION \.\+ 00 MAKE_FUNCTION \.\+
\\d\+ STORE_NAME f \\d\+ STORE_NAME f
\\d\+ MAKE_FUNCTION \.\+ \\d\+ MAKE_FUNCTION \.\+
@ -27,6 +27,11 @@ arg names:
\\d\+ DELETE_NAME Class \\d\+ DELETE_NAME Class
\\d\+ MAKE_FUNCTION \.\+ \\d\+ MAKE_FUNCTION \.\+
\\d\+ STORE_NAME f \\d\+ STORE_NAME f
\\d\+ LOAD_CONST_SMALL_INT 0
\\d\+ LOAD_CONST_STRING '*'
\\d\+ BUILD_TUPLE 1
\\d\+ IMPORT_NAME 'sys'
\\d\+ IMPORT_STAR
\\d\+ LOAD_CONST_NONE \\d\+ LOAD_CONST_NONE
\\d\+ RETURN_VALUE \\d\+ RETURN_VALUE
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
@ -300,11 +305,6 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
\\d\+ IMPORT_FROM 'b' \\d\+ IMPORT_FROM 'b'
\\d\+ STORE_DEREF 14 \\d\+ STORE_DEREF 14
\\d\+ POP_TOP \\d\+ POP_TOP
\\d\+ LOAD_CONST_SMALL_INT 0
\\d\+ LOAD_CONST_STRING '*'
\\d\+ BUILD_TUPLE 1
\\d\+ IMPORT_NAME 'a'
\\d\+ IMPORT_STAR
\\d\+ RAISE_LAST \\d\+ RAISE_LAST
\\d\+ LOAD_CONST_SMALL_INT 1 \\d\+ LOAD_CONST_SMALL_INT 1
\\d\+ RAISE_OBJ \\d\+ RAISE_OBJ

View File

@ -0,0 +1,13 @@
# test errors with import *
# 'import *' is not allowed in function scope
try:
exec('def foo(): from x import *')
except SyntaxError as er:
print('function', 'SyntaxError')
# 'import *' is not allowed in class scope
try:
exec('class C: from x import *')
except SyntaxError as er:
print('class', 'SyntaxError')