summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-12-22 20:35:40 +0100
committerBram Moolenaar <Bram@vim.org>2020-12-22 20:35:40 +0100
commit3bdc90b7dfab314768a8f56454ea62929524f05c (patch)
tree0836d782d16f1749ae745e5a6f87972d1c0f5073
parente5492609b3a153c631f1d600ecdef1af1c913bef (diff)
downloadvim-git-3bdc90b7dfab314768a8f56454ea62929524f05c.tar.gz
patch 8.2.2193: Vim9: can change constant in :def functionv8.2.2193
Problem: Vim9: can change constant in :def function. Solution: Check if a variable is locked. (issue #7526)
-rw-r--r--src/evalvars.c24
-rw-r--r--src/proto/evalvars.pro1
-rw-r--r--src/testdir/test_vim9_func.vim11
-rw-r--r--src/version.c2
-rw-r--r--src/vim9execute.c11
5 files changed, 39 insertions, 10 deletions
diff --git a/src/evalvars.c b/src/evalvars.c
index 572e5d556..ec3f508ed 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -3125,13 +3125,7 @@ set_var_const(
goto failed;
}
- // Check in this order for backwards compatibility:
- // - Whether the variable is read-only
- // - Whether the variable value is locked
- // - Whether the variable is locked
- if (var_check_ro(di->di_flags, name, FALSE)
- || value_check_lock(di->di_tv.v_lock, name, FALSE)
- || var_check_lock(di->di_flags, name, FALSE))
+ if (var_check_permission(di, name) == FAIL)
goto failed;
}
else
@@ -3243,6 +3237,22 @@ failed:
}
/*
+ * Check in this order for backwards compatibility:
+ * - Whether the variable is read-only
+ * - Whether the variable value is locked
+ * - Whether the variable is locked
+ */
+ int
+var_check_permission(dictitem_T *di, char_u *name)
+{
+ if (var_check_ro(di->di_flags, name, FALSE)
+ || value_check_lock(di->di_tv.v_lock, name, FALSE)
+ || var_check_lock(di->di_flags, name, FALSE))
+ return FAIL;
+ return OK;
+}
+
+/*
* Return TRUE if di_flags "flags" indicates variable "name" is read-only.
* Also give an error message.
*/
diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro
index 4c9d64582..c597ca372 100644
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -70,6 +70,7 @@ void vars_clear_ext(hashtab_T *ht, int free_val);
void delete_var(hashtab_T *ht, hashitem_T *hi);
void set_var(char_u *name, typval_T *tv, int copy);
void set_var_const(char_u *name, type_T *type, typval_T *tv_arg, int copy, int flags);
+int var_check_permission(dictitem_T *di, char_u *name);
int var_check_ro(int flags, char_u *name, int use_gettext);
int var_check_lock(int flags, char_u *name, int use_gettext);
int var_check_fixed(int flags, char_u *name, int use_gettext);
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index eadd1d1c3..bdced0257 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -1022,6 +1022,17 @@ def Test_vim9script_call_fail_const()
writefile(lines, 'Xcall_const.vim')
assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc')
delete('Xcall_const.vim')
+
+ lines =<< trim END
+ const g:Aconst = 77
+ def Change()
+ # comment
+ g:Aconst = 99
+ enddef
+ call Change()
+ unlet g:Aconst
+ END
+ CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2)
enddef
" Test that inside :function a Python function can be defined, :def is not
diff --git a/src/version.c b/src/version.c
index 7c9529b55..73a80aaf9 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 */
/**/
+ 2193,
+/**/
2192,
/**/
2191,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 9636cbffa..90b4e0ba6 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -1693,8 +1693,10 @@ call_def_function(
case ISN_STOREW:
case ISN_STORET:
{
- dictitem_T *di;
- hashtab_T *ht;
+ dictitem_T *di;
+ hashtab_T *ht;
+ char_u *name = iptr->isn_arg.string + 2;
+
switch (iptr->isn_type)
{
case ISN_STOREG:
@@ -1714,11 +1716,14 @@ call_def_function(
}
--ectx.ec_stack.ga_len;
- di = find_var_in_ht(ht, 0, iptr->isn_arg.string + 2, TRUE);
+ di = find_var_in_ht(ht, 0, name, TRUE);
if (di == NULL)
store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
else
{
+ SOURCING_LNUM = iptr->isn_lnum;
+ if (var_check_permission(di, name) == FAIL)
+ goto on_error;
clear_tv(&di->di_tv);
di->di_tv = *STACK_TV_BOT(0);
}