From 5e122b11eaee64bbece2ace08fc3f994d5f83f2e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Sep 2023 18:17:27 +1000 Subject: [PATCH] py/parse: Always free lexer even if an exception is raised. Fixes issue #3843. Signed-off-by: Damien George --- py/parse.c | 7 +++++-- tests/extmod/vfs_userfs.py | 7 +++++++ tests/extmod/vfs_userfs.py.exp | 5 +++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/py/parse.c b/py/parse.c index 0dd56e455..e86103ed8 100644 --- a/py/parse.c +++ b/py/parse.c @@ -1023,6 +1023,9 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, } mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { + // Set exception handler to free the lexer if an exception is raised. + MP_DEFINE_NLR_JUMP_CALLBACK_FUNCTION_1(ctx, mp_lexer_free, lex); + nlr_push_jump_callback(&ctx.callback, mp_call_function_1_from_nlr_jump_callback); // initialise parser and allocate memory for its stacks @@ -1370,8 +1373,8 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { m_del(rule_stack_t, parser.rule_stack, parser.rule_stack_alloc); m_del(mp_parse_node_t, parser.result_stack, parser.result_stack_alloc); - // we also free the lexer on behalf of the caller - mp_lexer_free(lex); + // Deregister exception handler and free the lexer. + nlr_pop_jump_callback(true); return parser.tree; } diff --git a/tests/extmod/vfs_userfs.py b/tests/extmod/vfs_userfs.py index 518373c70..91c355c3d 100644 --- a/tests/extmod/vfs_userfs.py +++ b/tests/extmod/vfs_userfs.py @@ -68,6 +68,7 @@ user_files = { "/data.txt": b"some data in a text file", "/usermod1.py": b"print('in usermod1')\nimport usermod2", "/usermod2.py": b"print('in usermod2')", + "/usermod3.py": b"syntax error", } os.mount(UserFS(user_files), "/userfs") @@ -79,6 +80,12 @@ print(f.read()) sys.path.append("/userfs") import usermod1 +# import a .py file with a syntax error (file should be closed on error) +try: + import usermod3 +except SyntaxError: + print("SyntaxError in usermod3") + # unmount and undo path addition os.umount("/userfs") sys.path.pop() diff --git a/tests/extmod/vfs_userfs.py.exp b/tests/extmod/vfs_userfs.py.exp index 00ddd95fc..be54da47c 100644 --- a/tests/extmod/vfs_userfs.py.exp +++ b/tests/extmod/vfs_userfs.py.exp @@ -10,3 +10,8 @@ stat /usermod2.py open /usermod2.py rb ioctl 4 0 in usermod2 +stat /usermod3 +stat /usermod3.py +open /usermod3.py rb +ioctl 4 0 +SyntaxError in usermod3