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 = &current_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 {