patch 9.0.2001: Vim9: segfault with islocked()

Commit: 
https://github.com/vim/vim/commit/9771b2a67f825bdc6e5c615141d22c665952dc86
Author: Ernie Rael <[email protected]>
Date:   Sat Oct 7 22:05:40 2023 +0200

    patch 9.0.2001: Vim9: segfault with islocked()
    
    Problem:  Vim9: segfault with islocked()
    Solution: Check that the lval pointer is not null for objects and
              class variables
    
    closes: #13295
    
    Signed-off-by: Christian Brabandt <[email protected]>
    Co-authored-by: Ernie Rael <[email protected]>

diff --git a/src/eval.c b/src/eval.c
index d9fbec234..93109effb 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1375,6 +1375,7 @@ get_lval(
                      && v_type != VAR_OBJECT
                      && v_type != VAR_CLASS)
        {
+           // TODO: have a message with obj/class, not just dict,
            if (!quiet)
                semsg(_(e_dot_can_only_be_used_on_dictionary_str), name);
            return NULL;
@@ -1385,6 +1386,7 @@ get_lval(
                && v_type != VAR_OBJECT
                && v_type != VAR_CLASS)
        {
+           // TODO: have a message with obj/class, not just dict/list/blob,
            if (!quiet)
                emsg(_(e_can_only_index_list_dictionary_or_blob));
            return NULL;
@@ -1739,10 +1741,6 @@ get_lval(
                    }
                }
 
-               // TODO: dont' check access if inside class
-               // TODO: is GLV_READ_ONLY the right thing to use
-               //           for class/object member access?
-               //           Probably in some cases. Need inside class check
                if (lp->ll_valtype == NULL)
                {
                    int         m_idx;
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 501ee0358..b840220bd 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -7347,6 +7347,22 @@ f_islocked(typval_T *argvars, typval_T *rettv)
                                                   || tv_islocked(&di->di_tv));
                }
            }
+           else if (lv.ll_object != NULL)
+           {
+               typval_T *tv = ((typval_T *)(lv.ll_object + 1)) + lv.ll_oi;
+               rettv->vval.v_number = tv_islocked(tv);
+#ifdef LOG_LOCKVAR
+               ch_log(NULL, "LKVAR: f_islocked(): name %s (obj)", lv.ll_name);
+#endif
+           }
+           else if (lv.ll_class != NULL)
+           {
+               typval_T *tv = &lv.ll_class->class_members_tv[lv.ll_oi];
+               rettv->vval.v_number = tv_islocked(tv);
+#ifdef LOG_LOCKVAR
+               ch_log(NULL, "LKVAR: f_islocked(): name %s (cl)", lv.ll_name);
+#endif
+           }
            else if (lv.ll_range)
                emsg(_(e_range_not_allowed));
            else if (lv.ll_newkey != NULL)
diff --git a/src/structs.h b/src/structs.h
index 680ed6dbd..ee688848e 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -4547,11 +4547,18 @@ typedef struct
  *     "tv"        points to the (first) list item value
  *     "li"        points to the (first) list item
  *     "range", "n1", "n2" and "empty2" indicate what items are used.
- * For a member in a class/object: TODO: verify fields
+ * For a plain class or object:
+ *     "name"      points to the variable name.
+ *     "exp_name"  is NULL.
+ *     "tv"        points to the variable
+ *     "is_root"   TRUE
+ * For a variable in a class/object: (class is not NULL)
  *     "name"      points to the (expanded) variable name.
  *     "exp_name"  NULL or non-NULL, to be freed later.
- *     "tv"        points to the (first) list item value
- *     "oi"        index into member array, see _type to determine which array
+ *     "tv"        May point to class/object variable.
+ *     "object"    object containing variable, NULL if class variable
+ *     "class"     class of object or class containing variable
+ *     "oi"        index into class/object of tv
  * For an existing Dict item:
  *     "name"      points to the (expanded) variable name.
  *     "exp_name"  NULL or non-NULL, to be freed later.
@@ -4591,8 +4598,8 @@ typedef struct lval_S
     object_T   *ll_object;     // The object or NULL, class is not NULL
     class_T    *ll_class;      // The class or NULL, object may be NULL
     int                ll_oi;          // The object/class member index
-    int                ll_is_root;     // Special case. ll_tv is lval_root,
-                               // ignore the rest.
+    int                ll_is_root;     // TRUE if ll_tv is the lval_root, like 
a
+                               // plain object/class. ll_tv is variable.
 } lval_T;
 
 /**
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 0e70c9f6f..555c46cc8 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -4161,6 +4161,86 @@ def Test_lockvar_general()
   v9.CheckSourceFailure(lines, 'E1333: Cannot access private variable "_v1" in 
class "C"')
 enddef
 
+" Test builtin islocked()
+def Test_lockvar_islocked()
+  # Can't lock class/object variable
+  # Lock class/object variable's value
+  # Lock item of variabl's value (a list item)
+  # varible is at index 1 within class/object
+  var lines =<< trim END
+    vim9script
+
+    class C
+      this.o0: list<list<number>> = [ [0],  [1],  [2]]
+      this.o1: list<list<number>> = [[10], [11], [12]]
+      static c0: list<list<number>> = [[20], [21], [22]]
+      static c1: list<list<number>> = [[30], [31], [32]]
+    endclass
+
+    def LockIt(arg: any)
+      lockvar arg
+    enddef
+
+    def UnlockIt(arg: any)
+      unlockvar arg
+    enddef
+
+    var obj = C.new()
+    #lockvar obj.o1         # can't lock something you can't write to
+
+    try
+      lockvar obj.o1         # can't lock something you can't write to
+      call assert_false(1, '"lockvar obj.o1" should have failed')
+    catch
+      call assert_exception('E1335:')
+    endtry
+
+    LockIt(obj.o1)         # but can lock it's value
+    assert_equal(1, islocked("obj.o1"))
+    assert_equal(1, islocked("obj.o1[0]"))
+    assert_equal(1, islocked("obj.o1[1]"))
+    UnlockIt(obj.o1)
+    assert_equal(0, islocked("obj.o1"))
+    assert_equal(0, islocked("obj.o1[0]"))
+
+    lockvar obj.o1[0]
+    assert_equal(0, islocked("obj.o1"))
+    assert_equal(1, islocked("obj.o1[0]"))
+    assert_equal(0, islocked("obj.o1[1]"))
+    unlockvar obj.o1[0]
+    assert_equal(0, islocked("obj.o1"))
+    assert_equal(0, islocked("obj.o1[0]"))
+
+    # Same thing, but with a static
+
+    try
+      lockvar C.c1         # can't lock something you can't write to
+      call assert_false(1, '"lockvar C.c1" should have failed')
+    catch
+      call assert_exception('E1335:')
+    endtry
+
+    LockIt(C.c1)         # but can lock it's value
+    assert_equal(1, islocked("C.c1"))
+    assert_equal(1, islocked("C.c1[0]"))
+    assert_equal(1, islocked("C.c1[1]"))
+    UnlockIt(C.c1)
+    assert_equal(0, islocked("C.c1"))
+    assert_equal(0, islocked("C.c1[0]"))
+
+    lockvar C.c1[0]
+    assert_equal(0, islocked("C.c1"))
+    assert_equal(1, islocked("C.c1[0]"))
+    assert_equal(0, islocked("C.c1[1]"))
+    unlockvar C.c1[0]
+    assert_equal(0, islocked("C.c1"))
+    assert_equal(0, islocked("C.c1[0]"))
+  END
+  v9.CheckSourceSuccess(lines)
+  lines =<< trim END
+  END
+enddef
+
 " Test for a private object method
 def Test_private_object_method()
   # Try calling a private method using an object (at the script level)
diff --git a/src/version.c b/src/version.c
index 5d1c1c944..e408dc1f7 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2001,
 /**/
     2000,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qpDhd-00CbKT-4X%40256bit.org.

Raspunde prin e-mail lui