summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-04-26 20:32:59 +0200
committerBram Moolenaar <Bram@vim.org>2021-04-26 20:32:59 +0200
commit5930ddcd25c3c31a323cdb1b74c228958e124527 (patch)
tree0455805bd0abf89a56486a68347b6c4927b2eaab
parentb98cec28d95b2184c64a0646458c1e62deb2524b (diff)
downloadvim-git-5930ddcd25c3c31a323cdb1b74c228958e124527.tar.gz
patch 8.2.2812: Vim9: still crash when using substitute expressionv8.2.2812
Problem: Vim9: still crash when using substitute expression. Solution: Put the instruction list in the stack frame. (closes #8154)
-rw-r--r--src/testdir/test_vim9_cmd.vim4
-rw-r--r--src/version.c2
-rw-r--r--src/vim9.h10
-rw-r--r--src/vim9execute.c10
4 files changed, 15 insertions, 11 deletions
diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim
index 5732e1eea..1e1a498bf 100644
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -1208,15 +1208,18 @@ def Test_substitute_expr()
CheckDefFailure(['s/from/\="x"/9'], 'E488:')
# When calling a function the right instruction list needs to be restored.
+ g:cond = true
var lines =<< trim END
vim9script
def Foo()
Bar([])
enddef
def Bar(l: list<number>)
+ if g:cond
s/^/\=Rep()/
for n in l[:]
endfor
+ endif
enddef
def Rep(): string
return 'rep'
@@ -1227,6 +1230,7 @@ def Test_substitute_expr()
bwipe!
END
CheckScriptSuccess(lines)
+ unlet g:cond
enddef
def Test_redir_to_var()
diff --git a/src/version.c b/src/version.c
index 35d7a59c2..71fa21808 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2812,
+/**/
2811,
/**/
2810,
diff --git a/src/vim9.h b/src/vim9.h
index bbed384c2..5dc0a8f8d 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -427,15 +427,17 @@ struct dfunc_S {
// Number of entries used by stack frame for a function call.
// - ec_dfunc_idx: function index
// - ec_iidx: instruction index
+// - ec_instr: instruction list pointer
// - ec_outer: stack used for closures
// - funclocal: function-local data
// - ec_frame_idx: previous frame index
#define STACK_FRAME_FUNC_OFF 0
#define STACK_FRAME_IIDX_OFF 1
-#define STACK_FRAME_OUTER_OFF 2
-#define STACK_FRAME_FUNCLOCAL_OFF 3
-#define STACK_FRAME_IDX_OFF 4
-#define STACK_FRAME_SIZE 5
+#define STACK_FRAME_INSTR_OFF 2
+#define STACK_FRAME_OUTER_OFF 3
+#define STACK_FRAME_FUNCLOCAL_OFF 4
+#define STACK_FRAME_IDX_OFF 5
+#define STACK_FRAME_SIZE 6
#ifdef DEFINE_VIM9_GLOBALS
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 7f6ce5f33..07812741e 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -279,6 +279,7 @@ call_dfunc(
// Store current execution state in stack frame for ISN_RETURN.
STACK_TV_BOT(STACK_FRAME_FUNC_OFF)->vval.v_number = ectx->ec_dfunc_idx;
STACK_TV_BOT(STACK_FRAME_IIDX_OFF)->vval.v_number = ectx->ec_iidx;
+ STACK_TV_BOT(STACK_FRAME_INSTR_OFF)->vval.v_string = (void *)ectx->ec_instr;
STACK_TV_BOT(STACK_FRAME_OUTER_OFF)->vval.v_string = (void *)ectx->ec_outer;
STACK_TV_BOT(STACK_FRAME_FUNCLOCAL_OFF)->vval.v_string = (void *)floc;
STACK_TV_BOT(STACK_FRAME_IDX_OFF)->vval.v_number = ectx->ec_frame_idx;
@@ -592,6 +593,8 @@ func_return(ectx_T *ectx)
ectx->ec_dfunc_idx = prev_dfunc_idx;
ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx
+ STACK_FRAME_IIDX_OFF)->vval.v_number;
+ ectx->ec_instr = (void *)STACK_TV(ectx->ec_frame_idx
+ + STACK_FRAME_INSTR_OFF)->vval.v_string;
ectx->ec_outer = (void *)STACK_TV(ectx->ec_frame_idx
+ STACK_FRAME_OUTER_OFF)->vval.v_string;
floc = (void *)STACK_TV(ectx->ec_frame_idx
@@ -599,13 +602,6 @@ func_return(ectx_T *ectx)
// restoring ec_frame_idx must be last
ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx
+ STACK_FRAME_IDX_OFF)->vval.v_number;
- ectx->ec_instr = INSTRUCTIONS(prev_dfunc);
-
- // If the call was inside an ISN_SUBSTITUTE instruction need to use its
- // list of instructions.
- if (ectx->ec_instr[ectx->ec_iidx - 1].isn_type == ISN_SUBSTITUTE)
- ectx->ec_instr = ectx->ec_instr[ectx->ec_iidx - 1]
- .isn_arg.subs.subs_instr;
if (floc == NULL)
ectx->ec_funclocal.floc_restore_cmdmod = FALSE;