Mercurial > vim
comparison src/vim9execute.c @ 21303:7c50dfe302f8 v8.2.1202
patch 8.2.1202: Vim9: crash when calling a closure from a builtin function
Commit: https://github.com/vim/vim/commit/08f7a41b0a280e5901eb4ee4bbfe682113863492
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Jul 13 20:41:08 2020 +0200
patch 8.2.1202: Vim9: crash when calling a closure from a builtin function
Problem: Vim9: crash when calling a closure from a builtin function.
Solution: Use the current execution context. (closes https://github.com/vim/vim/issues/6441)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 13 Jul 2020 20:45:04 +0200 |
parents | 883315e762b7 |
children | d636c7bbe9ab |
comparison
equal
deleted
inserted
replaced
21302:cc426acfb89d | 21303:7c50dfe302f8 |
---|---|
459 tv->vval.v_number = 0; | 459 tv->vval.v_number = 0; |
460 | 460 |
461 return OK; | 461 return OK; |
462 } | 462 } |
463 | 463 |
464 // Ugly global to avoid passing the execution context around through many | |
465 // layers. | |
466 static ectx_T *current_ectx = NULL; | |
467 | |
464 /* | 468 /* |
465 * Call a builtin function by index. | 469 * Call a builtin function by index. |
466 */ | 470 */ |
467 static int | 471 static int |
468 call_bfunc(int func_idx, int argcount, ectx_T *ectx) | 472 call_bfunc(int func_idx, int argcount, ectx_T *ectx) |
469 { | 473 { |
470 typval_T argvars[MAX_FUNC_ARGS]; | 474 typval_T argvars[MAX_FUNC_ARGS]; |
471 int idx; | 475 int idx; |
472 int did_emsg_before = did_emsg; | 476 int did_emsg_before = did_emsg; |
477 ectx_T *prev_ectx = current_ectx; | |
473 | 478 |
474 if (call_prepare(argcount, argvars, ectx) == FAIL) | 479 if (call_prepare(argcount, argvars, ectx) == FAIL) |
475 return FAIL; | 480 return FAIL; |
476 | 481 |
477 // Call the builtin function. | 482 // Call the builtin function. Set "current_ectx" so that when it |
483 // recursively invokes call_def_function() a closure context can be set. | |
484 current_ectx = ectx; | |
478 call_internal_func_by_idx(func_idx, argvars, STACK_TV_BOT(-1)); | 485 call_internal_func_by_idx(func_idx, argvars, STACK_TV_BOT(-1)); |
486 current_ectx = prev_ectx; | |
479 | 487 |
480 // Clear the arguments. | 488 // Clear the arguments. |
481 for (idx = 0; idx < argcount; ++idx) | 489 for (idx = 0; idx < argcount; ++idx) |
482 clear_tv(&argvars[idx]); | 490 clear_tv(&argvars[idx]); |
483 | 491 |
747 ectx.ec_frame_idx = ectx.ec_stack.ga_len; | 755 ectx.ec_frame_idx = ectx.ec_stack.ga_len; |
748 initial_frame_idx = ectx.ec_frame_idx; | 756 initial_frame_idx = ectx.ec_frame_idx; |
749 | 757 |
750 if (partial != NULL) | 758 if (partial != NULL) |
751 { | 759 { |
752 ectx.ec_outer_stack = partial->pt_ectx_stack; | 760 if (partial->pt_ectx_stack == NULL && current_ectx != NULL) |
753 ectx.ec_outer_frame = partial->pt_ectx_frame; | 761 { |
762 // TODO: is this always the right way? | |
763 ectx.ec_outer_stack = ¤t_ectx->ec_stack; | |
764 ectx.ec_outer_frame = current_ectx->ec_frame_idx; | |
765 } | |
766 else | |
767 { | |
768 ectx.ec_outer_stack = partial->pt_ectx_stack; | |
769 ectx.ec_outer_frame = partial->pt_ectx_frame; | |
770 } | |
754 } | 771 } |
755 | 772 |
756 // dummy frame entries | 773 // dummy frame entries |
757 for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) | 774 for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) |
758 { | 775 { |