Mercurial > vim
comparison src/vim9cmds.c @ 33393:016d8f863230 v9.0.1955
patch 9.0.1955: Vim9: lockvar issues with objects/classes
Commit: https://github.com/vim/vim/commit/ee865f37acab6cac2cee6a171d60e1b365f852b0
Author: Ernie Rael <errael@raelity.com>
Date: Fri Sep 29 19:53:55 2023 +0200
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>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 29 Sep 2023 20:00:07 +0200 |
parents | 6340c608ca54 |
children | 4a62e78803db |
comparison
equal
deleted
inserted
replaced
33392:3d3d0492824e | 33393:016d8f863230 |
---|---|
187 { | 187 { |
188 cctx_T *cctx = coookie; | 188 cctx_T *cctx = coookie; |
189 int cc = *name_end; | 189 int cc = *name_end; |
190 char_u *p = lvp->ll_name; | 190 char_u *p = lvp->ll_name; |
191 int ret = OK; | 191 int ret = OK; |
192 size_t len; | |
193 char_u *buf; | 192 char_u *buf; |
194 isntype_T isn = ISN_EXEC; | 193 isntype_T isn = ISN_EXEC; |
195 char *cmd = eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar"; | 194 char *cmd = eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar"; |
195 int is_arg = FALSE; | |
196 | |
197 #ifdef LOG_LOCKVAR | |
198 ch_log(NULL, "LKVAR: compile_lock_unlock(): cookie %p, name %s", | |
199 coookie, p); | |
200 #endif | |
196 | 201 |
197 if (cctx->ctx_skip == SKIP_YES) | 202 if (cctx->ctx_skip == SKIP_YES) |
198 return OK; | 203 return OK; |
199 | 204 |
200 if (*p == NUL) | 205 if (*p == NUL) |
205 | 210 |
206 // Cannot use :lockvar and :unlockvar on local variables. | 211 // Cannot use :lockvar and :unlockvar on local variables. |
207 if (p[1] != ':') | 212 if (p[1] != ':') |
208 { | 213 { |
209 char_u *end = find_name_end(p, NULL, NULL, FNE_CHECK_START); | 214 char_u *end = find_name_end(p, NULL, NULL, FNE_CHECK_START); |
210 | 215 // If name is is locally accessible, except for local var, |
211 if (lookup_local(p, end - p, NULL, cctx) == OK) | 216 // then put it on the stack to use with ISN_LOCKUNLOCK. |
212 { | 217 // This could be v.memb, v[idx_key]; bare class variable, |
213 char_u *s = p; | 218 // function arg. The local variable on the stack, will be passed |
214 | 219 // to ex_lockvar() indirectly. |
215 if (*end != '.' && *end != '[') | 220 |
221 char_u *name = NULL; | |
222 int len = end - p; | |
223 | |
224 if (lookup_local(p, len, NULL, cctx) == OK) | |
225 { | |
226 // Handle "this", "this.val", "anyvar[idx]" | |
227 if (*end != '.' && *end != '[' | |
228 && (len != 4 || STRNCMP("this", p, len) != 0)) | |
216 { | 229 { |
217 emsg(_(e_cannot_lock_unlock_local_variable)); | 230 emsg(_(e_cannot_lock_unlock_local_variable)); |
218 return FAIL; | 231 return FAIL; |
219 } | 232 } |
220 | 233 // Push the local on the stack, could be "this". |
221 // For "d.member" put the local variable on the stack, it will be | 234 name = p; |
222 // passed to ex_lockvar() indirectly. | 235 #ifdef LOG_LOCKVAR |
223 if (compile_load(&s, end, cctx, FALSE, FALSE) == FAIL) | 236 ch_log(NULL, "LKVAR: compile... lookup_local: name %s", name); |
237 #endif | |
238 } | |
239 if (name == NULL) | |
240 { | |
241 class_T *cl; | |
242 if (cctx_class_member_idx(cctx, p, len, &cl) >= 0) | |
243 { | |
244 if (*end != '.' && *end != '[') | |
245 { | |
246 // Push the class of the bare class variable name | |
247 name = cl->class_name; | |
248 len = STRLEN(name); | |
249 #ifdef LOG_LOCKVAR | |
250 ch_log(NULL, "LKVAR: compile... cctx_class_member: name %s", | |
251 name); | |
252 #endif | |
253 } | |
254 } | |
255 } | |
256 if (name == NULL) | |
257 { | |
258 int idx; | |
259 type_T *type; | |
260 // Can lockvar any function arg. | |
261 // TODO: test arg[idx]/arg.member | |
262 if (arg_exists(p, len, &idx, &type, NULL, cctx) == OK) | |
263 { | |
264 name = p; | |
265 is_arg = TRUE; | |
266 #ifdef LOG_LOCKVAR | |
267 ch_log(NULL, "LKVAR: compile... arg_exists: name %s", name); | |
268 #endif | |
269 } | |
270 } | |
271 if (name != NULL) | |
272 { | |
273 #ifdef LOG_LOCKVAR | |
274 ch_log(NULL, "LKVAR: compile... INS_LOCKUNLOCK %s", name); | |
275 #endif | |
276 if (compile_load(&name, name + len, cctx, FALSE, FALSE) == FAIL) | |
224 return FAIL; | 277 return FAIL; |
225 isn = ISN_LOCKUNLOCK; | 278 isn = ISN_LOCKUNLOCK; |
226 } | 279 } |
227 } | 280 } |
228 | 281 |
229 // Checking is done at runtime. | 282 // Checking is done at runtime. |
230 *name_end = NUL; | 283 *name_end = NUL; |
231 len = name_end - p + 20; | 284 size_t len = name_end - p + 20; |
232 buf = alloc(len); | 285 buf = alloc(len); |
233 if (buf == NULL) | 286 if (buf == NULL) |
234 ret = FAIL; | 287 ret = FAIL; |
235 else | 288 else |
236 { | 289 { |
237 if (deep < 0) | 290 if (deep < 0) |
238 vim_snprintf((char *)buf, len, "%s! %s", cmd, p); | 291 vim_snprintf((char *)buf, len, "%s! %s", cmd, p); |
239 else | 292 else |
240 vim_snprintf((char *)buf, len, "%s %d %s", cmd, deep, p); | 293 vim_snprintf((char *)buf, len, "%s %d %s", cmd, deep, p); |
241 ret = generate_EXEC_copy(cctx, isn, buf); | 294 #ifdef LOG_LOCKVAR |
295 ch_log(NULL, "LKVAR: compile... buf %s", buf); | |
296 #endif | |
297 if (isn == ISN_LOCKUNLOCK) | |
298 ret = generate_LOCKUNLOCK(cctx, buf, is_arg); | |
299 else | |
300 ret = generate_EXEC_copy(cctx, isn, buf); | |
242 | 301 |
243 vim_free(buf); | 302 vim_free(buf); |
244 *name_end = cc; | 303 *name_end = cc; |
245 } | 304 } |
246 return ret; | 305 return ret; |