changeset 32138:2c09e40ce3da v9.0.1400

patch 9.0.1400: find_file_in_path() is not reentrant Commit: https://github.com/vim/vim/commit/5145c9a829cd43cb9e7962b181bf99226eb3a53f Author: Bram Moolenaar <Bram@vim.org> 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)
author Bram Moolenaar <Bram@vim.org>
date Sat, 11 Mar 2023 15:00:04 +0100
parents 799e9cb2699d
children 91b362e3a2b7
files src/ex_docmd.c src/filepath.c src/findfile.c src/misc2.c src/proto/findfile.pro src/version.c
diffstat 6 files changed, 98 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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)
--- 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);
--- 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);
--- 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);
--- 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,