changeset 23295:d9ae7dd3a0f2 v8.2.2193

patch 8.2.2193: Vim9: can change constant in :def function Commit: https://github.com/vim/vim/commit/3bdc90b7dfab314768a8f56454ea62929524f05c Author: Bram Moolenaar <Bram@vim.org> Date: Tue Dec 22 20:35:40 2020 +0100 patch 8.2.2193: Vim9: can change constant in :def function Problem: Vim9: can change constant in :def function. Solution: Check if a variable is locked. (issue https://github.com/vim/vim/issues/7526)
author Bram Moolenaar <Bram@vim.org>
date Tue, 22 Dec 2020 20:45:04 +0100
parents 38b22245d35c
children c9123e2447bc
files src/evalvars.c src/proto/evalvars.pro src/testdir/test_vim9_func.vim src/version.c src/vim9execute.c
diffstat 5 files changed, 39 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- 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.
  */
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -70,6 +70,7 @@ void vars_clear_ext(hashtab_T *ht, int f
 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);
--- 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
--- 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,
--- 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);
 		    }