Mercurial > vim
comparison src/evalvars.c @ 22240:88927d5f275d v8.2.1669
patch 8.2.1669: Vim9: memory leak when storing a value fails
Commit: https://github.com/vim/vim/commit/b0fa5e17c587d9c71596bd10836918af713ffff6
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Sep 12 19:51:42 2020 +0200
patch 8.2.1669: Vim9: memory leak when storing a value fails
Problem: Vim9: memory leak when storing a value fails.
Solution: Free the value when not storing it.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 12 Sep 2020 20:00:04 +0200 |
parents | 7899b4e2880c |
children | 23f5750146d9 |
comparison
equal
deleted
inserted
replaced
22239:3e8d7529c28f | 22240:88927d5f275d |
---|---|
2948 | 2948 |
2949 ht = find_var_ht(name, &varname); | 2949 ht = find_var_ht(name, &varname); |
2950 if (ht == NULL || *varname == NUL) | 2950 if (ht == NULL || *varname == NUL) |
2951 { | 2951 { |
2952 semsg(_(e_illvar), name); | 2952 semsg(_(e_illvar), name); |
2953 return; | 2953 goto failed; |
2954 } | 2954 } |
2955 is_script_local = ht == get_script_local_ht(); | 2955 is_script_local = ht == get_script_local_ht(); |
2956 | 2956 |
2957 if (in_vim9script() | 2957 if (in_vim9script() |
2958 && !is_script_local | 2958 && !is_script_local |
2959 && (flags & LET_NO_COMMAND) == 0 | 2959 && (flags & LET_NO_COMMAND) == 0 |
2960 && name[1] == ':') | 2960 && name[1] == ':') |
2961 { | 2961 { |
2962 vim9_declare_error(name); | 2962 vim9_declare_error(name); |
2963 return; | 2963 goto failed; |
2964 } | 2964 } |
2965 | 2965 |
2966 di = find_var_in_ht(ht, 0, varname, TRUE); | 2966 di = find_var_in_ht(ht, 0, varname, TRUE); |
2967 | 2967 |
2968 // Search in parent scope which is possible to reference from lambda | 2968 // Search in parent scope which is possible to reference from lambda |
2969 if (di == NULL) | 2969 if (di == NULL) |
2970 di = find_var_in_scoped_ht(name, TRUE); | 2970 di = find_var_in_scoped_ht(name, TRUE); |
2971 | 2971 |
2972 if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) | 2972 if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) |
2973 && var_wrong_func_name(name, di == NULL)) | 2973 && var_wrong_func_name(name, di == NULL)) |
2974 return; | 2974 goto failed; |
2975 | 2975 |
2976 if (need_convert_to_bool(type, tv)) | 2976 if (need_convert_to_bool(type, tv)) |
2977 { | 2977 { |
2978 // Destination is a bool and the value is not, but it can be converted. | 2978 // Destination is a bool and the value is not, but it can be converted. |
2979 CLEAR_FIELD(bool_tv); | 2979 CLEAR_FIELD(bool_tv); |
2987 if ((di->di_flags & DI_FLAGS_RELOAD) == 0) | 2987 if ((di->di_flags & DI_FLAGS_RELOAD) == 0) |
2988 { | 2988 { |
2989 if (flags & LET_IS_CONST) | 2989 if (flags & LET_IS_CONST) |
2990 { | 2990 { |
2991 emsg(_(e_cannot_mod)); | 2991 emsg(_(e_cannot_mod)); |
2992 return; | 2992 goto failed; |
2993 } | 2993 } |
2994 | 2994 |
2995 if (is_script_local && in_vim9script()) | 2995 if (is_script_local && in_vim9script()) |
2996 { | 2996 { |
2997 if ((flags & LET_NO_COMMAND) == 0) | 2997 if ((flags & LET_NO_COMMAND) == 0) |
2998 { | 2998 { |
2999 semsg(_(e_redefining_script_item_str), name); | 2999 semsg(_(e_redefining_script_item_str), name); |
3000 return; | 3000 goto failed; |
3001 } | 3001 } |
3002 | 3002 |
3003 // check the type and adjust to bool if needed | 3003 // check the type and adjust to bool if needed |
3004 if (check_script_var_type(&di->di_tv, tv, name) == FAIL) | 3004 if (check_script_var_type(&di->di_tv, tv, name) == FAIL) |
3005 return; | 3005 goto failed; |
3006 } | 3006 } |
3007 | 3007 |
3008 if (var_check_ro(di->di_flags, name, FALSE) | 3008 if (var_check_ro(di->di_flags, name, FALSE) |
3009 || var_check_lock(di->di_tv.v_lock, name, FALSE)) | 3009 || var_check_lock(di->di_tv.v_lock, name, FALSE)) |
3010 return; | 3010 goto failed; |
3011 } | 3011 } |
3012 else | 3012 else |
3013 // can only redefine once | 3013 // can only redefine once |
3014 di->di_flags &= ~DI_FLAGS_RELOAD; | 3014 di->di_flags &= ~DI_FLAGS_RELOAD; |
3015 | 3015 |
3035 { | 3035 { |
3036 // Take over the string to avoid an extra alloc/free. | 3036 // Take over the string to avoid an extra alloc/free. |
3037 di->di_tv.vval.v_string = tv->vval.v_string; | 3037 di->di_tv.vval.v_string = tv->vval.v_string; |
3038 tv->vval.v_string = NULL; | 3038 tv->vval.v_string = NULL; |
3039 } | 3039 } |
3040 return; | 3040 goto failed; |
3041 } | 3041 } |
3042 else if (di->di_tv.v_type == VAR_NUMBER) | 3042 else if (di->di_tv.v_type == VAR_NUMBER) |
3043 { | 3043 { |
3044 di->di_tv.vval.v_number = tv_get_number(tv); | 3044 di->di_tv.vval.v_number = tv_get_number(tv); |
3045 if (STRCMP(varname, "searchforward") == 0) | 3045 if (STRCMP(varname, "searchforward") == 0) |
3049 { | 3049 { |
3050 no_hlsearch = !di->di_tv.vval.v_number; | 3050 no_hlsearch = !di->di_tv.vval.v_number; |
3051 redraw_all_later(SOME_VALID); | 3051 redraw_all_later(SOME_VALID); |
3052 } | 3052 } |
3053 #endif | 3053 #endif |
3054 return; | 3054 goto failed; |
3055 } | 3055 } |
3056 else if (di->di_tv.v_type != tv->v_type) | 3056 else if (di->di_tv.v_type != tv->v_type) |
3057 { | 3057 { |
3058 semsg(_("E963: setting %s to value with wrong type"), name); | 3058 semsg(_("E963: setting %s to value with wrong type"), name); |
3059 return; | 3059 goto failed; |
3060 } | 3060 } |
3061 } | 3061 } |
3062 | 3062 |
3063 clear_tv(&di->di_tv); | 3063 clear_tv(&di->di_tv); |
3064 } | 3064 } |
3066 { | 3066 { |
3067 // Can't add "v:" or "a:" variable. | 3067 // Can't add "v:" or "a:" variable. |
3068 if (ht == &vimvarht || ht == get_funccal_args_ht()) | 3068 if (ht == &vimvarht || ht == get_funccal_args_ht()) |
3069 { | 3069 { |
3070 semsg(_(e_illvar), name); | 3070 semsg(_(e_illvar), name); |
3071 return; | 3071 goto failed; |
3072 } | 3072 } |
3073 | 3073 |
3074 // Make sure the variable name is valid. | 3074 // Make sure the variable name is valid. |
3075 if (!valid_varname(varname)) | 3075 if (!valid_varname(varname)) |
3076 return; | 3076 goto failed; |
3077 | 3077 |
3078 di = alloc(sizeof(dictitem_T) + STRLEN(varname)); | 3078 di = alloc(sizeof(dictitem_T) + STRLEN(varname)); |
3079 if (di == NULL) | 3079 if (di == NULL) |
3080 return; | 3080 goto failed; |
3081 STRCPY(di->di_key, varname); | 3081 STRCPY(di->di_key, varname); |
3082 if (hash_add(ht, DI2HIKEY(di)) == FAIL) | 3082 if (hash_add(ht, DI2HIKEY(di)) == FAIL) |
3083 { | 3083 { |
3084 vim_free(di); | 3084 vim_free(di); |
3085 return; | 3085 goto failed; |
3086 } | 3086 } |
3087 di->di_flags = DI_FLAGS_ALLOC; | 3087 di->di_flags = DI_FLAGS_ALLOC; |
3088 if (flags & LET_IS_CONST) | 3088 if (flags & LET_IS_CONST) |
3089 di->di_flags |= DI_FLAGS_LOCK; | 3089 di->di_flags |= DI_FLAGS_LOCK; |
3090 | 3090 |
3126 if (flags & LET_IS_CONST) | 3126 if (flags & LET_IS_CONST) |
3127 // Like :lockvar! name: lock the value and what it contains, but only | 3127 // Like :lockvar! name: lock the value and what it contains, but only |
3128 // if the reference count is up to one. That locks only literal | 3128 // if the reference count is up to one. That locks only literal |
3129 // values. | 3129 // values. |
3130 item_lock(&di->di_tv, DICT_MAXNEST, TRUE, TRUE); | 3130 item_lock(&di->di_tv, DICT_MAXNEST, TRUE, TRUE); |
3131 return; | |
3132 failed: | |
3133 if (!copy) | |
3134 clear_tv(tv_arg); | |
3131 } | 3135 } |
3132 | 3136 |
3133 /* | 3137 /* |
3134 * Return TRUE if di_flags "flags" indicates variable "name" is read-only. | 3138 * Return TRUE if di_flags "flags" indicates variable "name" is read-only. |
3135 * Also give an error message. | 3139 * Also give an error message. |