mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
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 <cb@256bit.org> Co-authored-by: Ernie Rael <errael@raelity.com>
This commit is contained in:
parent
1087b8c29a
commit
9771b2a67f
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2001,
|
||||
/**/
|
||||
2000,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user