provider/RPC: apply_autocmds_group(): fix double-free

During provider dispatch, eval_call_provider() saves global
state--including pointers, such as `autocmd_fname`--into
`provider_caller_scope` which is later restored by f_rpcrequest().

But `autocmd_fname` is special-cased in eval_vars(), for performance
(see Vim patch 7.2.021; this is also the singular purpose of the
`autocmd_fname_full` global. Yay!)

If eval_vars() frees `autocmd_fname` then its provider-RPC-scoped alias
becomes a problem.

Solution: Don't free autocmd_fname in eval_vars(), just copy into it.

closes #5245
closes #5617

Reference
------------------------------------------------------------------------

Vim patch 7.2.021
f6dad43c98
Problem:    When executing autocommands getting the full file name may be
            slow. (David Kotchan)
Solution:   Postpone calling FullName_save() until autocmd_fname is used.

vim_dev discussion (2008): "Problem with CursorMoved AutoCommand when
Editing Files on a Remote WIndows Share"
https://groups.google.com/d/msg/vim_dev/kj95weZa_eE/GTgj4aq5sIgJ
This commit is contained in:
Justin M. Keyes
2018-03-20 23:57:41 +01:00
parent 9627325684
commit 189c5abeba
5 changed files with 49 additions and 19 deletions

View File

@@ -13828,7 +13828,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
save_autocmd_fname_full = autocmd_fname_full;
save_autocmd_bufnr = autocmd_bufnr;
save_funccalp = save_funccal();
//
current_SID = provider_caller_scope.SID;
sourcing_name = provider_caller_scope.sourcing_name;
sourcing_lnum = provider_caller_scope.sourcing_lnum;
@@ -22481,7 +22481,8 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
restore_funccal(provider_caller_scope.funccalp);
provider_caller_scope = saved_provider_caller_scope;
provider_call_nesting--;
assert(provider_call_nesting >= 0);
return rettv;
}

View File

@@ -8547,15 +8547,16 @@ eval_vars (
break;
case SPEC_AFILE: /* file name for autocommand */
result = autocmd_fname;
if (result != NULL && !autocmd_fname_full) {
/* Still need to turn the fname into a full path. It is
* postponed to avoid a delay when <afile> is not used. */
autocmd_fname_full = TRUE;
result = (char_u *)FullName_save((char *)autocmd_fname, FALSE);
xfree(autocmd_fname);
autocmd_fname = result;
if (autocmd_fname != NULL && !autocmd_fname_full) {
// Still need to turn the fname into a full path. It was
// postponed to avoid a delay when <afile> is not used.
autocmd_fname_full = true;
result = (char_u *)FullName_save((char *)autocmd_fname, false);
// Copy into `autocmd_fname`, don't reassign it. #8165
xstrlcpy((char *)autocmd_fname, (char *)result, MAXPATHL);
xfree(result);
}
result = autocmd_fname;
if (result == NULL) {
*errormsg = (char_u *)_(
"E495: no autocommand file name to substitute for \"<afile>\"");

View File

@@ -6755,7 +6755,8 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
autocmd_fname = fname_io;
}
if (autocmd_fname != NULL) {
autocmd_fname = vim_strsave(autocmd_fname);
// Allocate MAXPATHL for when eval_vars() resolves the fullpath.
autocmd_fname = vim_strnsave(autocmd_fname, MAXPATHL);
}
autocmd_fname_full = false; // call FullName_save() later