Mercurial > vim
comparison src/userfunc.c @ 23527:27ca5534a408 v8.2.2306
patch 8.2.2306: Vim9: when using function reference type is not checked
Commit: https://github.com/vim/vim/commit/32b3f820107139d7edf0c592bb06f090c3eb6c51
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Jan 6 21:59:39 2021 +0100
patch 8.2.2306: Vim9: when using function reference type is not checked
Problem: Vim9: when using function reference type is not checked.
Solution: When using a function reference lookup the type and check the
argument types. (issue #7629)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Wed, 06 Jan 2021 22:00:06 +0100 |
parents | 7e8703464f01 |
children | f39a18a42aed |
comparison
equal
deleted
inserted
replaced
23526:22fd43db29c8 | 23527:27ca5534a408 |
---|---|
725 /* | 725 /* |
726 * Check if "name" is a variable of type VAR_FUNC. If so, return the function | 726 * Check if "name" is a variable of type VAR_FUNC. If so, return the function |
727 * name it contains, otherwise return "name". | 727 * name it contains, otherwise return "name". |
728 * If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set | 728 * If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set |
729 * "partialp". | 729 * "partialp". |
730 * If "type" is not NULL and a Vim9 script-local variable is found look up the | |
731 * type of the variable. | |
730 */ | 732 */ |
731 char_u * | 733 char_u * |
732 deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload) | 734 deref_func_name( |
735 char_u *name, | |
736 int *lenp, | |
737 partial_T **partialp, | |
738 type_T **type, | |
739 int no_autoload) | |
733 { | 740 { |
734 dictitem_T *v; | 741 dictitem_T *v; |
735 int cc; | 742 int cc; |
736 char_u *s; | 743 char_u *s = NULL; |
744 hashtab_T *ht; | |
737 | 745 |
738 if (partialp != NULL) | 746 if (partialp != NULL) |
739 *partialp = NULL; | 747 *partialp = NULL; |
740 | 748 |
741 cc = name[*lenp]; | 749 cc = name[*lenp]; |
742 name[*lenp] = NUL; | 750 name[*lenp] = NUL; |
743 v = find_var(name, NULL, no_autoload); | 751 v = find_var(name, &ht, no_autoload); |
744 name[*lenp] = cc; | 752 name[*lenp] = cc; |
745 if (v != NULL && v->di_tv.v_type == VAR_FUNC) | 753 if (v != NULL) |
746 { | 754 { |
747 if (v->di_tv.vval.v_string == NULL) | 755 if (v->di_tv.v_type == VAR_FUNC) |
748 { | 756 { |
749 *lenp = 0; | 757 if (v->di_tv.vval.v_string == NULL) |
750 return (char_u *)""; // just in case | 758 { |
751 } | 759 *lenp = 0; |
752 s = v->di_tv.vval.v_string; | 760 return (char_u *)""; // just in case |
753 *lenp = (int)STRLEN(s); | 761 } |
754 return s; | 762 s = v->di_tv.vval.v_string; |
755 } | 763 *lenp = (int)STRLEN(s); |
756 | 764 } |
757 if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) | 765 |
758 { | 766 if (v->di_tv.v_type == VAR_PARTIAL) |
759 partial_T *pt = v->di_tv.vval.v_partial; | 767 { |
760 | 768 partial_T *pt = v->di_tv.vval.v_partial; |
761 if (pt == NULL) | 769 |
762 { | 770 if (pt == NULL) |
763 *lenp = 0; | 771 { |
764 return (char_u *)""; // just in case | 772 *lenp = 0; |
765 } | 773 return (char_u *)""; // just in case |
766 if (partialp != NULL) | 774 } |
767 *partialp = pt; | 775 if (partialp != NULL) |
768 s = partial_name(pt); | 776 *partialp = pt; |
769 *lenp = (int)STRLEN(s); | 777 s = partial_name(pt); |
770 return s; | 778 *lenp = (int)STRLEN(s); |
779 } | |
780 | |
781 if (s != NULL) | |
782 { | |
783 if (type != NULL && ht == get_script_local_ht()) | |
784 { | |
785 svar_T *sv = find_typval_in_script(&v->di_tv); | |
786 | |
787 if (sv != NULL) | |
788 *type = sv->sv_type; | |
789 } | |
790 return s; | |
791 } | |
771 } | 792 } |
772 | 793 |
773 return name; | 794 return name; |
774 } | 795 } |
775 | 796 |
2385 argvars = argv; | 2406 argvars = argv; |
2386 argcount = partial->pt_argc + argcount_in; | 2407 argcount = partial->pt_argc + argcount_in; |
2387 } | 2408 } |
2388 } | 2409 } |
2389 | 2410 |
2411 if (error == FCERR_NONE && funcexe->check_type != NULL && funcexe->evaluate) | |
2412 { | |
2413 // Check that the argument types are OK for the types of the funcref. | |
2414 if (check_argument_types(funcexe->check_type, argvars, argcount, | |
2415 name) == FAIL) | |
2416 error = FCERR_OTHER; | |
2417 } | |
2418 | |
2390 if (error == FCERR_NONE && funcexe->evaluate) | 2419 if (error == FCERR_NONE && funcexe->evaluate) |
2391 { | 2420 { |
2392 char_u *rfname = fname; | 2421 char_u *rfname = fname; |
2393 int is_global = FALSE; | 2422 int is_global = FALSE; |
2394 | 2423 |
2627 char_u **pp, | 2656 char_u **pp, |
2628 int *is_global, | 2657 int *is_global, |
2629 int skip, // only find the end, don't evaluate | 2658 int skip, // only find the end, don't evaluate |
2630 int flags, | 2659 int flags, |
2631 funcdict_T *fdp, // return: info about dictionary used | 2660 funcdict_T *fdp, // return: info about dictionary used |
2632 partial_T **partial) // return: partial of a FuncRef | 2661 partial_T **partial, // return: partial of a FuncRef |
2662 type_T **type) // return: type of funcref if not NULL | |
2633 { | 2663 { |
2634 char_u *name = NULL; | 2664 char_u *name = NULL; |
2635 char_u *start; | 2665 char_u *start; |
2636 char_u *end; | 2666 char_u *end; |
2637 int lead; | 2667 int lead; |
2731 | 2761 |
2732 // Check if the name is a Funcref. If so, use the value. | 2762 // Check if the name is a Funcref. If so, use the value. |
2733 if (lv.ll_exp_name != NULL) | 2763 if (lv.ll_exp_name != NULL) |
2734 { | 2764 { |
2735 len = (int)STRLEN(lv.ll_exp_name); | 2765 len = (int)STRLEN(lv.ll_exp_name); |
2736 name = deref_func_name(lv.ll_exp_name, &len, partial, | 2766 name = deref_func_name(lv.ll_exp_name, &len, partial, type, |
2737 flags & TFN_NO_AUTOLOAD); | 2767 flags & TFN_NO_AUTOLOAD); |
2738 if (name == lv.ll_exp_name) | 2768 if (name == lv.ll_exp_name) |
2739 name = NULL; | 2769 name = NULL; |
2740 } | 2770 } |
2741 else if (!(flags & TFN_NO_DEREF)) | 2771 else if (!(flags & TFN_NO_DEREF)) |
2742 { | 2772 { |
2743 len = (int)(end - *pp); | 2773 len = (int)(end - *pp); |
2744 name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD); | 2774 name = deref_func_name(*pp, &len, partial, type, |
2775 flags & TFN_NO_AUTOLOAD); | |
2745 if (name == *pp) | 2776 if (name == *pp) |
2746 name = NULL; | 2777 name = NULL; |
2747 } | 2778 } |
2748 if (name != NULL) | 2779 if (name != NULL) |
2749 { | 2780 { |
3062 CLEAR_FIELD(fudi); | 3093 CLEAR_FIELD(fudi); |
3063 } | 3094 } |
3064 else | 3095 else |
3065 { | 3096 { |
3066 name = trans_function_name(&p, &is_global, eap->skip, | 3097 name = trans_function_name(&p, &is_global, eap->skip, |
3067 TFN_NO_AUTOLOAD, &fudi, NULL); | 3098 TFN_NO_AUTOLOAD, &fudi, NULL, NULL); |
3068 paren = (vim_strchr(p, '(') != NULL); | 3099 paren = (vim_strchr(p, '(') != NULL); |
3069 if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) | 3100 if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) |
3070 { | 3101 { |
3071 /* | 3102 /* |
3072 * Return on an invalid expression in braces, unless the expression | 3103 * Return on an invalid expression in braces, unless the expression |
3477 || (eap->cmdidx == CMD_def && checkforcmd(&p, "def", 3))) | 3508 || (eap->cmdidx == CMD_def && checkforcmd(&p, "def", 3))) |
3478 { | 3509 { |
3479 if (*p == '!') | 3510 if (*p == '!') |
3480 p = skipwhite(p + 1); | 3511 p = skipwhite(p + 1); |
3481 p += eval_fname_script(p); | 3512 p += eval_fname_script(p); |
3482 vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL, NULL)); | 3513 vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL, |
3514 NULL, NULL)); | |
3483 if (*skipwhite(p) == '(') | 3515 if (*skipwhite(p) == '(') |
3484 { | 3516 { |
3485 if (nesting == MAX_FUNC_NESTING - 1) | 3517 if (nesting == MAX_FUNC_NESTING - 1) |
3486 emsg(_(e_function_nesting_too_deep)); | 3518 emsg(_(e_function_nesting_too_deep)); |
3487 else | 3519 else |
3614 */ | 3646 */ |
3615 if (fudi.fd_dict == NULL) | 3647 if (fudi.fd_dict == NULL) |
3616 { | 3648 { |
3617 hashtab_T *ht; | 3649 hashtab_T *ht; |
3618 | 3650 |
3619 v = find_var(name, &ht, FALSE); | 3651 v = find_var(name, &ht, TRUE); |
3620 if (v != NULL && v->di_tv.v_type == VAR_FUNC) | 3652 if (v != NULL && v->di_tv.v_type == VAR_FUNC) |
3621 { | 3653 { |
3622 emsg_funcname(N_("E707: Function name conflicts with variable: %s"), | 3654 emsg_funcname(N_("E707: Function name conflicts with variable: %s"), |
3623 name); | 3655 name); |
3624 goto erret; | 3656 goto erret; |
4005 int is_global = FALSE; | 4037 int is_global = FALSE; |
4006 | 4038 |
4007 flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD; | 4039 flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD; |
4008 if (no_deref) | 4040 if (no_deref) |
4009 flag |= TFN_NO_DEREF; | 4041 flag |= TFN_NO_DEREF; |
4010 p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL); | 4042 p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL, NULL); |
4011 nm = skipwhite(nm); | 4043 nm = skipwhite(nm); |
4012 | 4044 |
4013 // Only accept "funcname", "funcname ", "funcname (..." and | 4045 // Only accept "funcname", "funcname ", "funcname (..." and |
4014 // "funcname(...", not "funcname!...". | 4046 // "funcname(...", not "funcname!...". |
4015 if (p != NULL && (*nm == NUL || *nm == '(')) | 4047 if (p != NULL && (*nm == NUL || *nm == '(')) |
4025 char_u *nm = name; | 4057 char_u *nm = name; |
4026 char_u *p; | 4058 char_u *p; |
4027 int is_global = FALSE; | 4059 int is_global = FALSE; |
4028 | 4060 |
4029 p = trans_function_name(&nm, &is_global, FALSE, | 4061 p = trans_function_name(&nm, &is_global, FALSE, |
4030 TFN_INT|TFN_QUIET, NULL, NULL); | 4062 TFN_INT|TFN_QUIET, NULL, NULL, NULL); |
4031 | 4063 |
4032 if (p != NULL && *nm == NUL | 4064 if (p != NULL && *nm == NUL |
4033 && (!check || translated_function_exists(p, is_global))) | 4065 && (!check || translated_function_exists(p, is_global))) |
4034 return p; | 4066 return p; |
4035 | 4067 |
4095 char_u *name; | 4127 char_u *name; |
4096 funcdict_T fudi; | 4128 funcdict_T fudi; |
4097 int is_global = FALSE; | 4129 int is_global = FALSE; |
4098 | 4130 |
4099 p = eap->arg; | 4131 p = eap->arg; |
4100 name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi, NULL); | 4132 name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi, |
4133 NULL, NULL); | |
4101 vim_free(fudi.fd_newkey); | 4134 vim_free(fudi.fd_newkey); |
4102 if (name == NULL) | 4135 if (name == NULL) |
4103 { | 4136 { |
4104 if (fudi.fd_dict != NULL && !eap->skip) | 4137 if (fudi.fd_dict != NULL && !eap->skip) |
4105 emsg(_(e_funcref)); | 4138 emsg(_(e_funcref)); |
4326 int doesrange; | 4359 int doesrange; |
4327 int failed = FALSE; | 4360 int failed = FALSE; |
4328 funcdict_T fudi; | 4361 funcdict_T fudi; |
4329 partial_T *partial = NULL; | 4362 partial_T *partial = NULL; |
4330 evalarg_T evalarg; | 4363 evalarg_T evalarg; |
4364 type_T *type = NULL; | |
4331 | 4365 |
4332 fill_evalarg_from_eap(&evalarg, eap, eap->skip); | 4366 fill_evalarg_from_eap(&evalarg, eap, eap->skip); |
4333 if (eap->skip) | 4367 if (eap->skip) |
4334 { | 4368 { |
4335 // trans_function_name() doesn't work well when skipping, use eval0() | 4369 // trans_function_name() doesn't work well when skipping, use eval0() |
4341 --emsg_skip; | 4375 --emsg_skip; |
4342 clear_evalarg(&evalarg, eap); | 4376 clear_evalarg(&evalarg, eap); |
4343 return; | 4377 return; |
4344 } | 4378 } |
4345 | 4379 |
4346 tofree = trans_function_name(&arg, NULL, eap->skip, | 4380 tofree = trans_function_name(&arg, NULL, eap->skip, TFN_INT, |
4347 TFN_INT, &fudi, &partial); | 4381 &fudi, &partial, in_vim9script() ? &type : NULL); |
4348 if (fudi.fd_newkey != NULL) | 4382 if (fudi.fd_newkey != NULL) |
4349 { | 4383 { |
4350 // Still need to give an error message for missing key. | 4384 // Still need to give an error message for missing key. |
4351 semsg(_(e_dictkey), fudi.fd_newkey); | 4385 semsg(_(e_dictkey), fudi.fd_newkey); |
4352 vim_free(fudi.fd_newkey); | 4386 vim_free(fudi.fd_newkey); |
4361 | 4395 |
4362 // If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its | 4396 // If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its |
4363 // contents. For VAR_PARTIAL get its partial, unless we already have one | 4397 // contents. For VAR_PARTIAL get its partial, unless we already have one |
4364 // from trans_function_name(). | 4398 // from trans_function_name(). |
4365 len = (int)STRLEN(tofree); | 4399 len = (int)STRLEN(tofree); |
4366 name = deref_func_name(tofree, &len, | 4400 name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, |
4367 partial != NULL ? NULL : &partial, FALSE); | 4401 in_vim9script() && type == NULL ? &type : NULL, FALSE); |
4368 | 4402 |
4369 // Skip white space to allow ":call func ()". Not good, but required for | 4403 // Skip white space to allow ":call func ()". Not good, but required for |
4370 // backward compatibility. | 4404 // backward compatibility. |
4371 startarg = skipwhite(arg); | 4405 startarg = skipwhite(arg); |
4372 rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this | 4406 rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this |
4414 funcexe.lastline = eap->line2; | 4448 funcexe.lastline = eap->line2; |
4415 funcexe.doesrange = &doesrange; | 4449 funcexe.doesrange = &doesrange; |
4416 funcexe.evaluate = !eap->skip; | 4450 funcexe.evaluate = !eap->skip; |
4417 funcexe.partial = partial; | 4451 funcexe.partial = partial; |
4418 funcexe.selfdict = fudi.fd_dict; | 4452 funcexe.selfdict = fudi.fd_dict; |
4453 funcexe.check_type = type; | |
4419 if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL) | 4454 if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL) |
4420 { | 4455 { |
4421 failed = TRUE; | 4456 failed = TRUE; |
4422 break; | 4457 break; |
4423 } | 4458 } |