# HG changeset patch # User Bram Moolenaar # Date 1678543204 -3600 # Node ID 2c09e40ce3da53def022af9260f5dac9c297fe26 # Parent 799e9cb2699d3685254ee4e0ba1dbeae2139a41a patch 9.0.1400: find_file_in_path() is not reentrant Commit: https://github.com/vim/vim/commit/5145c9a829cd43cb9e7962b181bf99226eb3a53f Author: Bram Moolenaar Date: Sat Mar 11 13:55:53 2023 +0000 patch 9.0.1400: find_file_in_path() is not reentrant Problem: find_file_in_path() is not reentrant. Solution: Instead of global variables pass pointers to the functions. (closes #12093) diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -6767,8 +6767,13 @@ ex_splitview(exarg_T *eap) if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) { + char_u *file_to_find = NULL; + char *search_ctx = NULL; fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), - FNAME_MESS, TRUE, curbuf->b_ffname); + FNAME_MESS, TRUE, curbuf->b_ffname, + &file_to_find, &search_ctx); + vim_free(file_to_find); + vim_findfile_cleanup(search_ctx); if (fname == NULL) goto theend; eap->arg = fname; @@ -7032,21 +7037,25 @@ ex_find(exarg_T *eap) { char_u *fname; int count; + char_u *file_to_find = NULL; + char *search_ctx = NULL; fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS, - TRUE, curbuf->b_ffname); + TRUE, curbuf->b_ffname, &file_to_find, &search_ctx); if (eap->addr_count > 0) { - // Repeat finding the file "count" times. This matters when it - // appears several times in the path. + // Repeat finding the file "count" times. This matters when it appears + // several times in the path. count = eap->line2; while (fname != NULL && --count > 0) { vim_free(fname); fname = find_file_in_path(NULL, 0, FNAME_MESS, - FALSE, curbuf->b_ffname); - } - } + FALSE, curbuf->b_ffname, &file_to_find, &search_ctx); + } + } + VIM_CLEAR(file_to_find); + vim_findfile_cleanup(search_ctx); if (fname == NULL) return; @@ -7057,7 +7066,7 @@ ex_find(exarg_T *eap) } /* - * ":open" simulation: for now just work like ":visual". + * ":open" simulation: for now works just like ":visual". */ static void ex_open(exarg_T *eap) @@ -7138,13 +7147,6 @@ do_exedit( // Special case: ":global/pat/visual\NLvi-commands" if (global_busy) { - int rd = RedrawingDisabled; - int nwr = no_wait_return; - int ms = msg_scroll; -#ifdef FEAT_GUI - int he = hold_gui_events; -#endif - if (eap->nextcmd != NULL) { stuffReadbuff(eap->nextcmd); @@ -7153,11 +7155,15 @@ do_exedit( if (exmode_was != EXMODE_VIM) settmode(TMODE_RAW); + int save_rd = RedrawingDisabled; RedrawingDisabled = 0; + int save_nwr = no_wait_return; no_wait_return = 0; need_wait_return = FALSE; + int save_ms = msg_scroll; msg_scroll = 0; #ifdef FEAT_GUI + int save_he = hold_gui_events; hold_gui_events = 0; #endif set_must_redraw(UPD_CLEAR); @@ -7166,11 +7172,11 @@ do_exedit( main_loop(FALSE, TRUE); pending_exmode_active = FALSE; - RedrawingDisabled = rd; - no_wait_return = nwr; - msg_scroll = ms; + RedrawingDisabled = save_rd; + no_wait_return = save_nwr; + msg_scroll = save_ms; #ifdef FEAT_GUI - hold_gui_events = he; + hold_gui_events = save_he; #endif } return; diff --git a/src/filepath.c b/src/filepath.c --- a/src/filepath.c +++ b/src/filepath.c @@ -982,6 +982,9 @@ findfilendir( if (*fname != NUL && !error) { + char_u *file_to_find = NULL; + char *search_ctx = NULL; + do { if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) @@ -992,13 +995,17 @@ findfilendir( find_what, curbuf->b_ffname, find_what == FINDFILE_DIR - ? (char_u *)"" : curbuf->b_p_sua); + ? (char_u *)"" : curbuf->b_p_sua, + &file_to_find, &search_ctx); first = FALSE; if (fresult != NULL && rettv->v_type == VAR_LIST) list_append_string(rettv->vval.v_list, fresult, -1); } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); + + vim_free(file_to_find); + vim_findfile_cleanup(search_ctx); } if (rettv->v_type == VAR_STRING) diff --git a/src/findfile.c b/src/findfile.c --- a/src/findfile.c +++ b/src/findfile.c @@ -1571,23 +1571,21 @@ find_file_in_path( int len, // length of file name int options, int first, // use count'th matching file name - char_u *rel_fname) // file name searching relative to + char_u *rel_fname, // file name searching relative to + char_u **file_to_find, // in/out: modified copy of file name + char **search_ctx) // in/out: state of the search { return find_file_in_path_option(ptr, len, options, first, *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path, - FINDFILE_BOTH, rel_fname, curbuf->b_p_sua); + FINDFILE_BOTH, rel_fname, curbuf->b_p_sua, + file_to_find, search_ctx); } -static char_u *ff_file_to_find = NULL; -static void *fdip_search_ctx = NULL; - # if defined(EXITFREE) || defined(PROTO) void free_findfile(void) { - vim_free(ff_file_to_find); - vim_findfile_cleanup(fdip_search_ctx); - vim_free(ff_expand_buffer); + VIM_CLEAR(ff_expand_buffer); } # endif @@ -1607,10 +1605,13 @@ find_directory_in_path( char_u *ptr, // file name int len, // length of file name int options, - char_u *rel_fname) // file name searching relative to + char_u *rel_fname, // file name searching relative to + char_u **file_to_find, // in/out: modified copy of file name + char **search_ctx) // in/out: state of the search { return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath, - FINDFILE_DIR, rel_fname, (char_u *)""); + FINDFILE_DIR, rel_fname, (char_u *)"", + file_to_find, search_ctx); } char_u * @@ -1622,8 +1623,11 @@ find_file_in_path_option( char_u *path_option, // p_path or p_cdpath int find_what, // FINDFILE_FILE, _DIR or _BOTH char_u *rel_fname, // file name we are looking relative to. - char_u *suffixes) // list of suffixes, 'suffixesadd' option + char_u *suffixes, // list of suffixes, 'suffixesadd' option + char_u **file_to_find, // in/out: modified copy of file name + char **search_ctx_arg) // in/out: state of the search { + ff_search_ctx_T **search_ctx = (ff_search_ctx_T **)search_ctx_arg; static char_u *dir; static int did_findfile_init = FALSE; char_u save_char; @@ -1649,9 +1653,9 @@ find_file_in_path_option( expand_env_esc(ptr, NameBuff, MAXPATHL, FALSE, TRUE, NULL); ptr[len] = save_char; - vim_free(ff_file_to_find); - ff_file_to_find = vim_strsave(NameBuff); - if (ff_file_to_find == NULL) // out of memory + vim_free(*file_to_find); + *file_to_find = vim_strsave(NameBuff); + if (*file_to_find == NULL) // out of memory { file_name = NULL; goto theend; @@ -1659,30 +1663,30 @@ find_file_in_path_option( if (options & FNAME_UNESC) { // Change all "\ " to " ". - for (ptr = ff_file_to_find; *ptr != NUL; ++ptr) + for (ptr = *file_to_find; *ptr != NUL; ++ptr) if (ptr[0] == '\\' && ptr[1] == ' ') mch_memmove(ptr, ptr + 1, STRLEN(ptr)); } } - rel_to_curdir = (ff_file_to_find[0] == '.' - && (ff_file_to_find[1] == NUL - || vim_ispathsep(ff_file_to_find[1]) - || (ff_file_to_find[1] == '.' - && (ff_file_to_find[2] == NUL - || vim_ispathsep(ff_file_to_find[2]))))); - if (vim_isAbsName(ff_file_to_find) + rel_to_curdir = ((*file_to_find)[0] == '.' + && ((*file_to_find)[1] == NUL + || vim_ispathsep((*file_to_find)[1]) + || ((*file_to_find)[1] == '.' + && ((*file_to_find)[2] == NUL + || vim_ispathsep((*file_to_find)[2]))))); + if (vim_isAbsName(*file_to_find) // "..", "../path", "." and "./path": don't use the path_option || rel_to_curdir # if defined(MSWIN) // handle "\tmp" as absolute path - || vim_ispathsep(ff_file_to_find[0]) + || vim_ispathsep((*file_to_find)[0]) // handle "c:name" as absolute path - || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':') + || ((*file_to_find)[0] != NUL && (*file_to_find)[1] == ':') # endif # ifdef AMIGA // handle ":tmp" as absolute path - || ff_file_to_find[0] == ':' + || (*file_to_find)[0] == ':' # endif ) { @@ -1696,9 +1700,9 @@ find_file_in_path_option( int l; int run; - if (path_with_url(ff_file_to_find)) + if (path_with_url(*file_to_find)) { - file_name = vim_strsave(ff_file_to_find); + file_name = vim_strsave(*file_to_find); goto theend; } @@ -1706,7 +1710,7 @@ find_file_in_path_option( // Otherwise or when this fails use the current directory. for (run = 1; run <= 2; ++run) { - l = (int)STRLEN(ff_file_to_find); + l = (int)STRLEN(*file_to_find); if (run == 1 && rel_to_curdir && (options & FNAME_REL) @@ -1714,12 +1718,12 @@ find_file_in_path_option( && STRLEN(rel_fname) + l < MAXPATHL) { STRCPY(NameBuff, rel_fname); - STRCPY(gettail(NameBuff), ff_file_to_find); + STRCPY(gettail(NameBuff), *file_to_find); l = (int)STRLEN(NameBuff); } else { - STRCPY(NameBuff, ff_file_to_find); + STRCPY(NameBuff, *file_to_find); run = 2; } @@ -1753,7 +1757,7 @@ find_file_in_path_option( if (first == TRUE) { // vim_findfile_free_visited can handle a possible NULL pointer - vim_findfile_free_visited(fdip_search_ctx); + vim_findfile_free_visited(*search_ctx); dir = path_option; did_findfile_init = FALSE; } @@ -1762,7 +1766,7 @@ find_file_in_path_option( { if (did_findfile_init) { - file_name = vim_findfile(fdip_search_ctx); + file_name = vim_findfile(*search_ctx); if (file_name != NULL) break; @@ -1776,8 +1780,8 @@ find_file_in_path_option( { // We searched all paths of the option, now we can // free the search context. - vim_findfile_cleanup(fdip_search_ctx); - fdip_search_ctx = NULL; + vim_findfile_cleanup(*search_ctx); + *search_ctx = NULL; break; } @@ -1790,10 +1794,10 @@ find_file_in_path_option( // get the stopdir string r_ptr = vim_findfile_stopdir(buf); - fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find, + *search_ctx = vim_findfile_init(buf, *file_to_find, r_ptr, 100, FALSE, find_what, - fdip_search_ctx, FALSE, rel_fname); - if (fdip_search_ctx != NULL) + *search_ctx, FALSE, rel_fname); + if (*search_ctx != NULL) did_findfile_init = TRUE; vim_free(buf); } @@ -1804,20 +1808,17 @@ find_file_in_path_option( if (first == TRUE) { if (find_what == FINDFILE_DIR) - semsg(_(e_cant_find_directory_str_in_cdpath), - ff_file_to_find); + semsg(_(e_cant_find_directory_str_in_cdpath), *file_to_find); else - semsg(_(e_cant_find_file_str_in_path), - ff_file_to_find); + semsg(_(e_cant_find_file_str_in_path), *file_to_find); } else { if (find_what == FINDFILE_DIR) semsg(_(e_no_more_directory_str_found_in_cdpath), - ff_file_to_find); + *file_to_find); else - semsg(_(e_no_more_file_str_found_in_path), - ff_file_to_find); + semsg(_(e_no_more_file_str_found_in_path), *file_to_find); } } @@ -2046,8 +2047,11 @@ find_file_name_in_path( if (options & FNAME_EXP) { + char_u *file_to_find = NULL; + char *search_ctx = NULL; + file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, - TRUE, rel_fname); + TRUE, rel_fname, &file_to_find, &search_ctx); # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL) /* @@ -2063,7 +2067,7 @@ find_file_name_in_path( ptr = tofree; len = (int)STRLEN(ptr); file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, - TRUE, rel_fname); + TRUE, rel_fname, &file_to_find, &search_ctx); } } # endif @@ -2080,8 +2084,12 @@ find_file_name_in_path( while (file_name != NULL && --count > 0) { vim_free(file_name); - file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname); + file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname, + &file_to_find, &search_ctx); } + + vim_free(file_to_find); + vim_findfile_cleanup(search_ctx); } else file_name = vim_strnsave(ptr, len); diff --git a/src/misc2.c b/src/misc2.c --- a/src/misc2.c +++ b/src/misc2.c @@ -2473,9 +2473,13 @@ vim_chdir(char_u *new_dir) { char_u *dir_name; int r; + char_u *file_to_find = NULL; + char *search_ctx = NULL; dir_name = find_directory_in_path(new_dir, (int)STRLEN(new_dir), - FNAME_MESS, curbuf->b_ffname); + FNAME_MESS, curbuf->b_ffname, &file_to_find, &search_ctx); + vim_free(file_to_find); + vim_findfile_cleanup(search_ctx); if (dir_name == NULL) return -1; r = mch_chdir((char *)dir_name); diff --git a/src/proto/findfile.pro b/src/proto/findfile.pro --- a/src/proto/findfile.pro +++ b/src/proto/findfile.pro @@ -3,10 +3,10 @@ void *vim_findfile_init(char_u *path, ch char_u *vim_findfile_stopdir(char_u *buf); void vim_findfile_cleanup(void *ctx); char_u *vim_findfile(void *search_ctx_arg); -char_u *find_file_in_path(char_u *ptr, int len, int options, int first, char_u *rel_fname); +char_u *find_file_in_path(char_u *ptr, int len, int options, int first, char_u *rel_fname, char_u **file_to_find, char **search_ctx); void free_findfile(void); -char_u *find_directory_in_path(char_u *ptr, int len, int options, char_u *rel_fname); -char_u *find_file_in_path_option(char_u *ptr, int len, int options, int first, char_u *path_option, int find_what, char_u *rel_fname, char_u *suffixes); +char_u *find_directory_in_path(char_u *ptr, int len, int options, char_u *rel_fname, char_u **file_to_find, char **search_ctx); +char_u *find_file_in_path_option(char_u *ptr, int len, int options, int first, char_u *path_option, int find_what, char_u *rel_fname, char_u *suffixes, char_u **file_to_find, char **search_ctx_arg); char_u *grab_file_name(long count, linenr_T *file_lnum); char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum); char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u *rel_fname, linenr_T *file_lnum); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1400, +/**/ 1399, /**/ 1398,