0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 9.0.1955: Vim9: lockvar issues with objects/classes

Problem:  Vim9: lockvar issues with objects/classes
Solution: fix `get_lhs()` object/class access and avoid `SEGV`,
          make error messages more accurate.

- `get_lval()` detects/returns object/class access
- `compile_lock_unlock()` generate code for bare static and obj_arg access
- `do_lock_var()` check lval for `ll_object`/`ll_class` and fail if so.

Details:
- Add `ll_object`/`ll_class`/`ll_oi` to `lval_T`.
- Add `lockunlock_T` to `isn_T` for `is_arg` to specify handling of `lval_root` in `get_lval()`.
- In `get_lval()`, fill in `ll_object`/`ll_class`/`ll_oi` as needed; when no `[idx] or .key`, check lval_root on the way out.
- In `do_lock_var()` check for `ll_object`/`ll_class`; also bullet proof ll_dict case
  and give `Dictionay required` if problem. (not needed to avoid lockvar crash anymore)
- In `compile_lock_unlock()` compile for the class variable and func arg cases.

closes: #13174

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Ernie Rael <errael@raelity.com>
This commit is contained in:
Ernie Rael
2023-09-29 19:53:55 +02:00
committed by Christian Brabandt
parent 112431f217
commit ee865f37ac
12 changed files with 776 additions and 27 deletions

View File

@@ -189,10 +189,15 @@ compile_lock_unlock(
int cc = *name_end;
char_u *p = lvp->ll_name;
int ret = OK;
size_t len;
char_u *buf;
isntype_T isn = ISN_EXEC;
char *cmd = eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar";
int is_arg = FALSE;
#ifdef LOG_LOCKVAR
ch_log(NULL, "LKVAR: compile_lock_unlock(): cookie %p, name %s",
coookie, p);
#endif
if (cctx->ctx_skip == SKIP_YES)
return OK;
@@ -207,20 +212,68 @@ compile_lock_unlock(
if (p[1] != ':')
{
char_u *end = find_name_end(p, NULL, NULL, FNE_CHECK_START);
// If name is is locally accessible, except for local var,
// then put it on the stack to use with ISN_LOCKUNLOCK.
// This could be v.memb, v[idx_key]; bare class variable,
// function arg. The local variable on the stack, will be passed
// to ex_lockvar() indirectly.
if (lookup_local(p, end - p, NULL, cctx) == OK)
char_u *name = NULL;
int len = end - p;
if (lookup_local(p, len, NULL, cctx) == OK)
{
char_u *s = p;
if (*end != '.' && *end != '[')
// Handle "this", "this.val", "anyvar[idx]"
if (*end != '.' && *end != '['
&& (len != 4 || STRNCMP("this", p, len) != 0))
{
emsg(_(e_cannot_lock_unlock_local_variable));
return FAIL;
}
// For "d.member" put the local variable on the stack, it will be
// passed to ex_lockvar() indirectly.
if (compile_load(&s, end, cctx, FALSE, FALSE) == FAIL)
// Push the local on the stack, could be "this".
name = p;
#ifdef LOG_LOCKVAR
ch_log(NULL, "LKVAR: compile... lookup_local: name %s", name);
#endif
}
if (name == NULL)
{
class_T *cl;
if (cctx_class_member_idx(cctx, p, len, &cl) >= 0)
{
if (*end != '.' && *end != '[')
{
// Push the class of the bare class variable name
name = cl->class_name;
len = STRLEN(name);
#ifdef LOG_LOCKVAR
ch_log(NULL, "LKVAR: compile... cctx_class_member: name %s",
name);
#endif
}
}
}
if (name == NULL)
{
int idx;
type_T *type;
// Can lockvar any function arg.
// TODO: test arg[idx]/arg.member
if (arg_exists(p, len, &idx, &type, NULL, cctx) == OK)
{
name = p;
is_arg = TRUE;
#ifdef LOG_LOCKVAR
ch_log(NULL, "LKVAR: compile... arg_exists: name %s", name);
#endif
}
}
if (name != NULL)
{
#ifdef LOG_LOCKVAR
ch_log(NULL, "LKVAR: compile... INS_LOCKUNLOCK %s", name);
#endif
if (compile_load(&name, name + len, cctx, FALSE, FALSE) == FAIL)
return FAIL;
isn = ISN_LOCKUNLOCK;
}
@@ -228,7 +281,7 @@ compile_lock_unlock(
// Checking is done at runtime.
*name_end = NUL;
len = name_end - p + 20;
size_t len = name_end - p + 20;
buf = alloc(len);
if (buf == NULL)
ret = FAIL;
@@ -238,7 +291,13 @@ compile_lock_unlock(
vim_snprintf((char *)buf, len, "%s! %s", cmd, p);
else
vim_snprintf((char *)buf, len, "%s %d %s", cmd, deep, p);
ret = generate_EXEC_copy(cctx, isn, buf);
#ifdef LOG_LOCKVAR
ch_log(NULL, "LKVAR: compile... buf %s", buf);
#endif
if (isn == ISN_LOCKUNLOCK)
ret = generate_LOCKUNLOCK(cctx, buf, is_arg);
else
ret = generate_EXEC_copy(cctx, isn, buf);
vim_free(buf);
*name_end = cc;