To: vim_dev@googlegroups.com Subject: Patch 8.2.1161 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1161 Problem: Vim9: using freed memory. Solution: Put pointer back in evalarg instead of freeing it. Files: src/userfunc.c, src/vim9compile.c, src/eval.c, src/proto/eval.pro, src/structs.h *** ../vim-8.2.1160/src/userfunc.c 2020-07-08 19:35:17.767686401 +0200 --- src/userfunc.c 2020-07-08 21:33:04.828727980 +0200 *************** *** 389,396 **** partial_T *pt = NULL; int varargs; int ret; ! char_u *start; ! char_u *s, *e; int *old_eval_lavars = eval_lavars_used; int eval_lavars = FALSE; char_u *tofree = NULL; --- 389,396 ---- partial_T *pt = NULL; int varargs; int ret; ! char_u *s; ! char_u *start, *end; int *old_eval_lavars = eval_lavars_used; int eval_lavars = FALSE; char_u *tofree = NULL; *************** *** 399,408 **** ga_init(&newlines); // First, check if this is a lambda expression. "->" must exist. ! start = skipwhite(*arg + 1); ! ret = get_function_args(&start, '-', NULL, NULL, NULL, NULL, TRUE, NULL, NULL); ! if (ret == FAIL || *start != '>') return NOTDONE; // Parse the arguments again. --- 399,408 ---- ga_init(&newlines); // First, check if this is a lambda expression. "->" must exist. ! s = skipwhite(*arg + 1); ! ret = get_function_args(&s, '-', NULL, NULL, NULL, NULL, TRUE, NULL, NULL); ! if (ret == FAIL || *s != '>') return NOTDONE; // Parse the arguments again. *************** *** 423,430 **** // Get the start and the end of the expression. *arg = skipwhite_and_linebreak(*arg + 1, evalarg); ! s = *arg; ! ret = skip_expr_concatenate(&s, arg, evalarg); if (ret == FAIL) goto errret; if (evalarg != NULL) --- 423,430 ---- // Get the start and the end of the expression. *arg = skipwhite_and_linebreak(*arg + 1, evalarg); ! start = *arg; ! ret = skip_expr_concatenate(arg, &start, &end, evalarg); if (ret == FAIL) goto errret; if (evalarg != NULL) *************** *** 434,440 **** evalarg->eval_tofree = NULL; } - e = *arg; *arg = skipwhite_and_linebreak(*arg, evalarg); if (**arg != '}') { --- 434,439 ---- *************** *** 463,475 **** goto errret; // Add "return " before the expression. ! len = 7 + (int)(e - s) + 1; p = alloc(len); if (p == NULL) goto errret; ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p; STRCPY(p, "return "); ! vim_strncpy(p + 7, s, e - s); if (strstr((char *)p + 7, "a:") == NULL) // No a: variables are used for sure. flags |= FC_NOARGS; --- 462,474 ---- goto errret; // Add "return " before the expression. ! len = 7 + (int)(end - start) + 1; p = alloc(len); if (p == NULL) goto errret; ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p; STRCPY(p, "return "); ! vim_strncpy(p + 7, start, end - start); if (strstr((char *)p + 7, "a:") == NULL) // No a: variables are used for sure. flags |= FC_NOARGS; *************** *** 509,515 **** } eval_lavars_used = old_eval_lavars; ! vim_free(tofree); return OK; errret: --- 508,517 ---- } eval_lavars_used = old_eval_lavars; ! if (evalarg->eval_tofree == NULL) ! evalarg->eval_tofree = tofree; ! else ! vim_free(tofree); return OK; errret: *************** *** 517,523 **** ga_clear_strings(&newlines); vim_free(fp); vim_free(pt); ! vim_free(tofree); eval_lavars_used = old_eval_lavars; return FAIL; } --- 519,528 ---- ga_clear_strings(&newlines); vim_free(fp); vim_free(pt); ! if (evalarg->eval_tofree == NULL) ! evalarg->eval_tofree = tofree; ! else ! vim_free(tofree); eval_lavars_used = old_eval_lavars; return FAIL; } *** ../vim-8.2.1160/src/vim9compile.c 2020-07-08 19:35:17.767686401 +0200 --- src/vim9compile.c 2020-07-08 21:08:44.792351587 +0200 *************** *** 3113,3118 **** --- 3113,3120 ---- // Compile it into instructions. compile_def_function(ufunc, TRUE, cctx); + clear_evalarg(&evalarg, NULL); + if (ufunc->uf_def_status == UF_COMPILED) return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx); return FAIL; *** ../vim-8.2.1160/src/eval.c 2020-07-08 17:36:17.738105000 +0200 --- src/eval.c 2020-07-08 21:55:37.633123734 +0200 *************** *** 379,388 **** * Skip over an expression at "*pp". * If in Vim9 script and line breaks are encountered, the lines are * concatenated. "evalarg->eval_tofree" will be set accordingly. * Return FAIL for an error, OK otherwise. */ int ! skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg) { typval_T rettv; int res; --- 379,395 ---- * Skip over an expression at "*pp". * If in Vim9 script and line breaks are encountered, the lines are * concatenated. "evalarg->eval_tofree" will be set accordingly. + * "arg" is advanced to just after the expression. + * "start" is set to the start of the expression, "end" to just after the end. + * Also when the expression is copied to allocated memory. * Return FAIL for an error, OK otherwise. */ int ! skip_expr_concatenate( ! char_u **arg, ! char_u **start, ! char_u **end, ! evalarg_T *evalarg) { typval_T rettv; int res; *************** *** 398,409 **** if (ga_grow(gap, 1) == OK) ++gap->ga_len; } // Don't evaluate the expression. if (evalarg != NULL) evalarg->eval_flags &= ~EVAL_EVALUATE; ! *end = skipwhite(*end); ! res = eval1(end, &rettv, evalarg); if (evalarg != NULL) evalarg->eval_flags = save_flags; --- 405,418 ---- if (ga_grow(gap, 1) == OK) ++gap->ga_len; } + *start = *arg; // Don't evaluate the expression. if (evalarg != NULL) evalarg->eval_flags &= ~EVAL_EVALUATE; ! *arg = skipwhite(*arg); ! res = eval1(arg, &rettv, evalarg); ! *end = *arg; if (evalarg != NULL) evalarg->eval_flags = save_flags; *************** *** 419,425 **** else { char_u *p; ! size_t endoff = STRLEN(*end); // Line breaks encountered, concatenate all the lines. *((char_u **)gap->ga_data) = *start; --- 428,434 ---- else { char_u *p; ! size_t endoff = STRLEN(*arg); // Line breaks encountered, concatenate all the lines. *((char_u **)gap->ga_data) = *start; *************** *** 428,434 **** --- 437,450 ---- // free the lines only when using getsourceline() if (evalarg->eval_cookie != NULL) { + // Do not free the first line, the caller can still use it. *((char_u **)gap->ga_data) = NULL; + // Do not free the last line, "arg" points into it, free it + // later. + vim_free(evalarg->eval_tofree); + evalarg->eval_tofree = + ((char_u **)gap->ga_data)[gap->ga_len - 1]; + ((char_u **)gap->ga_data)[gap->ga_len - 1] = NULL; ga_clear_strings(gap); } else *************** *** 437,444 **** if (p == NULL) return FAIL; *start = p; ! vim_free(evalarg->eval_tofree); ! evalarg->eval_tofree = p; // Compute "end" relative to the end. *end = *start + STRLEN(*start) - endoff; } --- 453,460 ---- if (p == NULL) return FAIL; *start = p; ! vim_free(evalarg->eval_tofree_lambda); ! evalarg->eval_tofree_lambda = p; // Compute "end" relative to the end. *end = *start + STRLEN(*start) - endoff; } *************** *** 1936,1942 **** ((char_u **)gap->ga_data)[gap->ga_len] = line; ++gap->ga_len; } ! else { vim_free(evalarg->eval_tofree); evalarg->eval_tofree = line; --- 1952,1958 ---- ((char_u **)gap->ga_data)[gap->ga_len] = line; ++gap->ga_len; } ! else if (evalarg->eval_cookie != NULL) { vim_free(evalarg->eval_tofree); evalarg->eval_tofree = line; *************** *** 1962,1986 **** } /* ! * After using "evalarg" filled from "eap" free the memory. */ void clear_evalarg(evalarg_T *evalarg, exarg_T *eap) { ! if (evalarg != NULL && evalarg->eval_tofree != NULL) { ! if (eap != NULL) { ! // We may need to keep the original command line, e.g. for ! // ":let" it has the variable names. But we may also need the ! // new one, "nextcmd" points into it. Keep both. ! vim_free(eap->cmdline_tofree); ! eap->cmdline_tofree = *eap->cmdlinep; ! *eap->cmdlinep = evalarg->eval_tofree; } ! else ! vim_free(evalarg->eval_tofree); ! evalarg->eval_tofree = NULL; } } --- 1978,2008 ---- } /* ! * After using "evalarg" filled from "eap": free the memory. */ void clear_evalarg(evalarg_T *evalarg, exarg_T *eap) { ! if (evalarg != NULL) { ! if (evalarg->eval_tofree != NULL) { ! if (eap != NULL) ! { ! // We may need to keep the original command line, e.g. for ! // ":let" it has the variable names. But we may also need the ! // new one, "nextcmd" points into it. Keep both. ! vim_free(eap->cmdline_tofree); ! eap->cmdline_tofree = *eap->cmdlinep; ! *eap->cmdlinep = evalarg->eval_tofree; ! } ! else ! vim_free(evalarg->eval_tofree); ! evalarg->eval_tofree = NULL; } ! ! vim_free(evalarg->eval_tofree_lambda); ! evalarg->eval_tofree_lambda = NULL; } } *** ../vim-8.2.1160/src/proto/eval.pro 2020-07-04 14:14:55.633073475 +0200 --- src/proto/eval.pro 2020-07-08 21:35:36.700364651 +0200 *************** *** 10,16 **** int eval_expr_to_bool(typval_T *expr, int *error); char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip); int skip_expr(char_u **pp); ! int skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg); char_u *eval_to_string(char_u *arg, int convert); char_u *eval_to_string_safe(char_u *arg, int use_sandbox); varnumber_T eval_to_number(char_u *expr); --- 10,16 ---- int eval_expr_to_bool(typval_T *expr, int *error); char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip); int skip_expr(char_u **pp); ! int skip_expr_concatenate(char_u **arg, char_u **start, char_u **end, evalarg_T *evalarg); char_u *eval_to_string(char_u *arg, int convert); char_u *eval_to_string_safe(char_u *arg, int use_sandbox); varnumber_T eval_to_number(char_u *expr); *** ../vim-8.2.1160/src/structs.h 2020-07-08 17:36:17.734105013 +0200 --- src/structs.h 2020-07-08 21:54:48.377262186 +0200 *************** *** 1773,1780 **** // "eval_ga.ga_data" is a list of pointers to lines. garray_T eval_ga; ! // pointer to the line obtained with getsourceline() char_u *eval_tofree; } evalarg_T; // Flags for expression evaluation. --- 1773,1783 ---- // "eval_ga.ga_data" is a list of pointers to lines. garray_T eval_ga; ! // pointer to the last line obtained with getsourceline() char_u *eval_tofree; + + // pointer to the lines concatenated for a lambda. + char_u *eval_tofree_lambda; } evalarg_T; // Flags for expression evaluation. *** ../vim-8.2.1160/src/version.c 2020-07-08 19:35:17.767686401 +0200 --- src/version.c 2020-07-08 21:07:20.828519290 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1161, /**/ -- Normal people believe that if it ain't broke, don't fix it. Engineers believe that if it ain't broke, it doesn't have enough features yet. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///