comparison src/userfunc.c @ 26747:a8a4e1e7b111 v8.2.3902

patch 8.2.3902: Vim9: double free with nested :def function Commit: https://github.com/vim/vim/commit/9c23f9bb5fe435b28245ba8ac65aa0ca6b902c04 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Dec 26 14:23:22 2021 +0000 patch 8.2.3902: Vim9: double free with nested :def function Problem: Vim9: double free with nested :def function. Solution: Pass "line_to_free" from compile_def_function() and make sure cmdlinep is valid.
author Bram Moolenaar <Bram@vim.org>
date Sun, 26 Dec 2021 15:30:02 +0100
parents 9c9b8d95b05f
children 3a2b222107a6
comparison
equal deleted inserted replaced
26746:57551c0135af 26747:a8a4e1e7b111
718 line_arg = p + 1; 718 line_arg = p + 1;
719 } 719 }
720 } 720 }
721 else 721 else
722 { 722 {
723 vim_free(*line_to_free);
724 if (eap->getline == NULL) 723 if (eap->getline == NULL)
725 theline = getcmdline(':', 0L, indent, getline_options); 724 theline = getcmdline(':', 0L, indent, getline_options);
726 else 725 else
727 theline = eap->getline(':', eap->cookie, indent, 726 theline = eap->getline(':', eap->cookie, indent,
728 getline_options); 727 getline_options);
728 if (*eap->cmdlinep == *line_to_free)
729 *eap->cmdlinep = theline;
730 vim_free(*line_to_free);
729 *line_to_free = theline; 731 *line_to_free = theline;
730 } 732 }
731 if (KeyTyped) 733 if (KeyTyped)
732 lines_left = Rows - 1; 734 lines_left = Rows - 1;
733 if (theline == NULL) 735 if (theline == NULL)
835 { 837 {
836 // Another command follows. If the line came from "eap" 838 // Another command follows. If the line came from "eap"
837 // we can simply point into it, otherwise we need to 839 // we can simply point into it, otherwise we need to
838 // change "eap->cmdlinep". 840 // change "eap->cmdlinep".
839 eap->nextcmd = nextcmd; 841 eap->nextcmd = nextcmd;
840 if (*line_to_free != NULL) 842 if (*line_to_free != NULL
843 && *eap->cmdlinep != *line_to_free)
841 { 844 {
842 vim_free(*eap->cmdlinep); 845 vim_free(*eap->cmdlinep);
843 *eap->cmdlinep = *line_to_free; 846 *eap->cmdlinep = *line_to_free;
844 *line_to_free = NULL; 847 *line_to_free = NULL;
845 } 848 }
1159 ((char_u **)gap->ga_data)[gap->ga_len++] = pnl; 1162 ((char_u **)gap->ga_data)[gap->ga_len++] = pnl;
1160 ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl; 1163 ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl;
1161 } 1164 }
1162 if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL) 1165 if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL)
1163 goto erret; 1166 goto erret;
1164 if (cmdline != NULL) 1167 if (eap.nextcmd != NULL)
1165 // more is following after the "}", which was skipped 1168 // more is following after the "}", which was skipped
1166 last = cmdline; 1169 last = cmdline;
1167 else 1170 else
1168 // nothing is following the "}" 1171 // nothing is following the "}"
1169 last = (char_u *)"}"; 1172 last = (char_u *)"}";
1173 mch_memmove(pnl + 1, last, plen + 1); 1176 mch_memmove(pnl + 1, last, plen + 1);
1174 ((char_u **)gap->ga_data)[gap->ga_len++] = pnl; 1177 ((char_u **)gap->ga_data)[gap->ga_len++] = pnl;
1175 ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl; 1178 ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl;
1176 } 1179 }
1177 1180
1178 if (cmdline != NULL) 1181 if (eap.nextcmd != NULL)
1179 { 1182 {
1180 garray_T *tfgap = &evalarg->eval_tofree_ga; 1183 garray_T *tfgap = &evalarg->eval_tofree_ga;
1181 1184
1182 // Something comes after the "}". 1185 // Something comes after the "}".
1183 *arg = eap.nextcmd; 1186 *arg = eap.nextcmd;
1185 // "arg" points into cmdline, need to keep the line and free it later. 1188 // "arg" points into cmdline, need to keep the line and free it later.
1186 if (ga_grow(tfgap, 1) == OK) 1189 if (ga_grow(tfgap, 1) == OK)
1187 { 1190 {
1188 ((char_u **)(tfgap->ga_data))[tfgap->ga_len++] = cmdline; 1191 ((char_u **)(tfgap->ga_data))[tfgap->ga_len++] = cmdline;
1189 evalarg->eval_using_cmdline = TRUE; 1192 evalarg->eval_using_cmdline = TRUE;
1193 if (cmdline == line_to_free)
1194 line_to_free = NULL;
1190 } 1195 }
1191 } 1196 }
1192 else 1197 else
1193 *arg = (char_u *)""; 1198 *arg = (char_u *)"";
1194 1199
3986 * When "name_arg" is not NULL this is a nested function, using "name_arg" for 3991 * When "name_arg" is not NULL this is a nested function, using "name_arg" for
3987 * the function name. 3992 * the function name.
3988 * Returns a pointer to the function or NULL if no function defined. 3993 * Returns a pointer to the function or NULL if no function defined.
3989 */ 3994 */
3990 ufunc_T * 3995 ufunc_T *
3991 define_function(exarg_T *eap, char_u *name_arg) 3996 define_function(exarg_T *eap, char_u *name_arg, char_u **line_to_free)
3992 { 3997 {
3993 char_u *line_to_free = NULL;
3994 int j; 3998 int j;
3995 int c; 3999 int c;
3996 int saved_did_emsg; 4000 int saved_did_emsg;
3997 char_u *name = name_arg; 4001 char_u *name = name_arg;
3998 int is_global = FALSE; 4002 int is_global = FALSE;
4256 // invalid. 4260 // invalid.
4257 ++p; 4261 ++p;
4258 if (get_function_args(&p, ')', &newargs, 4262 if (get_function_args(&p, ')', &newargs,
4259 eap->cmdidx == CMD_def ? &argtypes : NULL, FALSE, 4263 eap->cmdidx == CMD_def ? &argtypes : NULL, FALSE,
4260 NULL, &varargs, &default_args, eap->skip, 4264 NULL, &varargs, &default_args, eap->skip,
4261 eap, &line_to_free) == FAIL) 4265 eap, line_to_free) == FAIL)
4262 goto errret_2; 4266 goto errret_2;
4263 whitep = p; 4267 whitep = p;
4264 4268
4265 if (eap->cmdidx == CMD_def) 4269 if (eap->cmdidx == CMD_def)
4266 { 4270 {
4366 // Save the starting line number. 4370 // Save the starting line number.
4367 sourcing_lnum_top = SOURCING_LNUM; 4371 sourcing_lnum_top = SOURCING_LNUM;
4368 4372
4369 // Do not define the function when getting the body fails and when 4373 // Do not define the function when getting the body fails and when
4370 // skipping. 4374 // skipping.
4371 if (get_function_body(eap, &newlines, line_arg, &line_to_free) == FAIL 4375 if (get_function_body(eap, &newlines, line_arg, line_to_free) == FAIL
4372 || eap->skip) 4376 || eap->skip)
4373 goto erret; 4377 goto erret;
4374 4378
4375 /* 4379 /*
4376 * If there are no errors, add the function 4380 * If there are no errors, add the function
4658 vim_free(fp); 4662 vim_free(fp);
4659 fp = NULL; 4663 fp = NULL;
4660 } 4664 }
4661 ret_free: 4665 ret_free:
4662 ga_clear_strings(&argtypes); 4666 ga_clear_strings(&argtypes);
4663 vim_free(line_to_free);
4664 vim_free(fudi.fd_newkey); 4667 vim_free(fudi.fd_newkey);
4665 if (name != name_arg) 4668 if (name != name_arg)
4666 vim_free(name); 4669 vim_free(name);
4667 vim_free(ret_type); 4670 vim_free(ret_type);
4668 did_emsg |= saved_did_emsg; 4671 did_emsg |= saved_did_emsg;
4674 * ":function" 4677 * ":function"
4675 */ 4678 */
4676 void 4679 void
4677 ex_function(exarg_T *eap) 4680 ex_function(exarg_T *eap)
4678 { 4681 {
4679 (void)define_function(eap, NULL); 4682 char_u *line_to_free = NULL;
4683
4684 (void)define_function(eap, NULL, &line_to_free);
4685 vim_free(line_to_free);
4680 } 4686 }
4681 4687
4682 /* 4688 /*
4683 * :defcompile - compile all :def functions in the current script that need to 4689 * :defcompile - compile all :def functions in the current script that need to
4684 * be compiled. Except dead functions. Doesn't do profiling. 4690 * be compiled. Except dead functions. Doesn't do profiling.