Mercurial > vim
comparison src/userfunc.c @ 23285:112fa621b127 v8.2.2188
patch 8.2.2188: Vim9: crash when calling global function from :def function
Commit: https://github.com/vim/vim/commit/cd45ed03bfdd7fac53d562ad402df74bd26e7754
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Dec 22 17:35:54 2020 +0100
patch 8.2.2188: Vim9: crash when calling global function from :def function
Problem: Vim9: crash when calling global function from :def function.
Solution: Set the outer context. Define the partial for the context on the
original function. Use a refcount to keep track of which ufunc is
using a dfunc. (closes #7525)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 22 Dec 2020 17:45:03 +0100 |
parents | 35583da6397e |
children | c76240efdf02 |
comparison
equal
deleted
inserted
replaced
23284:3d54c7fa353c | 23285:112fa621b127 |
---|---|
1258 fp->uf_cleared = TRUE; | 1258 fp->uf_cleared = TRUE; |
1259 | 1259 |
1260 // clear this function | 1260 // clear this function |
1261 func_clear_items(fp); | 1261 func_clear_items(fp); |
1262 funccal_unref(fp->uf_scoped, fp, force); | 1262 funccal_unref(fp->uf_scoped, fp, force); |
1263 if ((fp->uf_flags & FC_COPY) == 0) | 1263 unlink_def_function(fp); |
1264 clear_def_function(fp); | |
1265 } | 1264 } |
1266 | 1265 |
1267 /* | 1266 /* |
1268 * Free a function and remove it from the list of functions. Does not free | 1267 * Free a function and remove it from the list of functions. Does not free |
1269 * what a function contains, call func_clear() first. | 1268 * what a function contains, call func_clear() first. |
1305 } | 1304 } |
1306 | 1305 |
1307 /* | 1306 /* |
1308 * Copy already defined function "lambda" to a new function with name "global". | 1307 * Copy already defined function "lambda" to a new function with name "global". |
1309 * This is for when a compiled function defines a global function. | 1308 * This is for when a compiled function defines a global function. |
1310 * Caller should take care of adding a partial for a closure. | 1309 */ |
1311 */ | 1310 int |
1312 ufunc_T * | 1311 copy_func(char_u *lambda, char_u *global, ectx_T *ectx) |
1313 copy_func(char_u *lambda, char_u *global) | |
1314 { | 1312 { |
1315 ufunc_T *ufunc = find_func_even_dead(lambda, TRUE, NULL); | 1313 ufunc_T *ufunc = find_func_even_dead(lambda, TRUE, NULL); |
1316 ufunc_T *fp = NULL; | 1314 ufunc_T *fp = NULL; |
1317 | 1315 |
1318 if (ufunc == NULL) | 1316 if (ufunc == NULL) |
1317 { | |
1319 semsg(_(e_lambda_function_not_found_str), lambda); | 1318 semsg(_(e_lambda_function_not_found_str), lambda); |
1320 else | 1319 return FAIL; |
1321 { | 1320 } |
1322 // TODO: handle ! to overwrite | 1321 |
1323 fp = find_func(global, TRUE, NULL); | 1322 // TODO: handle ! to overwrite |
1324 if (fp != NULL) | 1323 fp = find_func(global, TRUE, NULL); |
1325 { | 1324 if (fp != NULL) |
1326 semsg(_(e_funcexts), global); | 1325 { |
1327 return NULL; | 1326 semsg(_(e_funcexts), global); |
1328 } | 1327 return FAIL; |
1329 | 1328 } |
1330 fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(global) + 1); | 1329 |
1331 if (fp == NULL) | 1330 fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(global) + 1); |
1332 return NULL; | 1331 if (fp == NULL) |
1333 | 1332 return FAIL; |
1334 fp->uf_varargs = ufunc->uf_varargs; | 1333 |
1335 fp->uf_flags = (ufunc->uf_flags & ~FC_VIM9) | FC_COPY; | 1334 fp->uf_varargs = ufunc->uf_varargs; |
1336 fp->uf_def_status = ufunc->uf_def_status; | 1335 fp->uf_flags = (ufunc->uf_flags & ~FC_VIM9) | FC_COPY; |
1337 fp->uf_dfunc_idx = ufunc->uf_dfunc_idx; | 1336 fp->uf_def_status = ufunc->uf_def_status; |
1338 if (ga_copy_strings(&ufunc->uf_args, &fp->uf_args) == FAIL | 1337 fp->uf_dfunc_idx = ufunc->uf_dfunc_idx; |
1339 || ga_copy_strings(&ufunc->uf_def_args, &fp->uf_def_args) | 1338 if (ga_copy_strings(&ufunc->uf_args, &fp->uf_args) == FAIL |
1340 == FAIL | 1339 || ga_copy_strings(&ufunc->uf_def_args, &fp->uf_def_args) |
1341 || ga_copy_strings(&ufunc->uf_lines, &fp->uf_lines) == FAIL) | 1340 == FAIL |
1341 || ga_copy_strings(&ufunc->uf_lines, &fp->uf_lines) == FAIL) | |
1342 goto failed; | |
1343 | |
1344 fp->uf_name_exp = ufunc->uf_name_exp == NULL ? NULL | |
1345 : vim_strsave(ufunc->uf_name_exp); | |
1346 if (ufunc->uf_arg_types != NULL) | |
1347 { | |
1348 fp->uf_arg_types = ALLOC_MULT(type_T *, fp->uf_args.ga_len); | |
1349 if (fp->uf_arg_types == NULL) | |
1342 goto failed; | 1350 goto failed; |
1343 | 1351 mch_memmove(fp->uf_arg_types, ufunc->uf_arg_types, |
1344 fp->uf_name_exp = ufunc->uf_name_exp == NULL ? NULL | 1352 sizeof(type_T *) * fp->uf_args.ga_len); |
1345 : vim_strsave(ufunc->uf_name_exp); | 1353 } |
1346 if (ufunc->uf_arg_types != NULL) | 1354 if (ufunc->uf_def_arg_idx != NULL) |
1347 { | 1355 { |
1348 fp->uf_arg_types = ALLOC_MULT(type_T *, fp->uf_args.ga_len); | 1356 fp->uf_def_arg_idx = ALLOC_MULT(int, fp->uf_def_args.ga_len + 1); |
1349 if (fp->uf_arg_types == NULL) | 1357 if (fp->uf_def_arg_idx == NULL) |
1350 goto failed; | 1358 goto failed; |
1351 mch_memmove(fp->uf_arg_types, ufunc->uf_arg_types, | 1359 mch_memmove(fp->uf_def_arg_idx, ufunc->uf_def_arg_idx, |
1352 sizeof(type_T *) * fp->uf_args.ga_len); | 1360 sizeof(int) * fp->uf_def_args.ga_len + 1); |
1353 } | 1361 } |
1354 if (ufunc->uf_def_arg_idx != NULL) | 1362 if (ufunc->uf_va_name != NULL) |
1355 { | 1363 { |
1356 fp->uf_def_arg_idx = ALLOC_MULT(int, fp->uf_def_args.ga_len + 1); | 1364 fp->uf_va_name = vim_strsave(ufunc->uf_va_name); |
1357 if (fp->uf_def_arg_idx == NULL) | 1365 if (fp->uf_va_name == NULL) |
1358 goto failed; | 1366 goto failed; |
1359 mch_memmove(fp->uf_def_arg_idx, ufunc->uf_def_arg_idx, | 1367 } |
1360 sizeof(int) * fp->uf_def_args.ga_len + 1); | 1368 fp->uf_ret_type = ufunc->uf_ret_type; |
1361 } | 1369 |
1362 if (ufunc->uf_va_name != NULL) | 1370 fp->uf_refcount = 1; |
1363 { | 1371 STRCPY(fp->uf_name, global); |
1364 fp->uf_va_name = vim_strsave(ufunc->uf_va_name); | 1372 hash_add(&func_hashtab, UF2HIKEY(fp)); |
1365 if (fp->uf_va_name == NULL) | 1373 |
1366 goto failed; | 1374 // the referenced dfunc_T is now used one more time |
1367 } | 1375 link_def_function(fp); |
1368 fp->uf_ret_type = ufunc->uf_ret_type; | 1376 |
1369 | 1377 // Create a partial to store the context of the function, if not done |
1370 fp->uf_refcount = 1; | 1378 // already. |
1371 STRCPY(fp->uf_name, global); | 1379 if ((ufunc->uf_flags & FC_CLOSURE) && ufunc->uf_partial == NULL) |
1372 hash_add(&func_hashtab, UF2HIKEY(fp)); | 1380 { |
1373 } | 1381 partial_T *pt = ALLOC_CLEAR_ONE(partial_T); |
1374 return fp; | 1382 |
1383 if (pt == NULL) | |
1384 goto failed; | |
1385 if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL) | |
1386 goto failed; | |
1387 ufunc->uf_partial = pt; | |
1388 --pt->pt_refcount; // not referenced here yet | |
1389 } | |
1390 if (ufunc->uf_partial != NULL) | |
1391 { | |
1392 fp->uf_partial = ufunc->uf_partial; | |
1393 ++fp->uf_partial->pt_refcount; | |
1394 } | |
1395 | |
1396 return OK; | |
1375 | 1397 |
1376 failed: | 1398 failed: |
1377 func_clear_free(fp, TRUE); | 1399 func_clear_free(fp, TRUE); |
1378 return NULL; | 1400 return FAIL; |
1379 } | 1401 } |
1380 | 1402 |
1381 static int funcdepth = 0; | 1403 static int funcdepth = 0; |
1382 | 1404 |
1383 /* | 1405 /* |
3513 fp->uf_flags &= ~FC_DEAD; | 3535 fp->uf_flags &= ~FC_DEAD; |
3514 #ifdef FEAT_PROFILE | 3536 #ifdef FEAT_PROFILE |
3515 fp->uf_profiling = FALSE; | 3537 fp->uf_profiling = FALSE; |
3516 fp->uf_prof_initialized = FALSE; | 3538 fp->uf_prof_initialized = FALSE; |
3517 #endif | 3539 #endif |
3518 clear_def_function(fp); | 3540 unlink_def_function(fp); |
3519 } | 3541 } |
3520 } | 3542 } |
3521 } | 3543 } |
3522 else | 3544 else |
3523 { | 3545 { |