Patch 9.0.1400
Problem:    find_file_in_path() is not reentrant.
Solution:   Instead of global variables pass pointers to the functions.
            (closes #12093)
Files:      src/findfile.c, src/proto/findfile.pro, src/filepath.c,
            src/ex_docmd.c, src/misc2.c


*** ../vim-9.0.1399/src/findfile.c      2023-02-01 13:11:11.710991162 +0000
--- src/findfile.c      2023-03-11 13:42:42.523776690 +0000
***************
*** 1571,1593 ****
      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
  {
      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);
  }
  
- 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);
  }
  # endif
  
--- 1571,1591 ----
      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    **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,
!           file_to_find, search_ctx);
  }
  
  # if defined(EXITFREE) || defined(PROTO)
      void
  free_findfile(void)
  {
!     VIM_CLEAR(ff_expand_buffer);
  }
  # endif
  
***************
*** 1607,1616 ****
      char_u    *ptr,           // file name
      int               len,            // length of file name
      int               options,
!     char_u    *rel_fname)     // file name searching relative to
  {
      return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath,
!                                      FINDFILE_DIR, rel_fname, (char_u *)"");
  }
  
      char_u *
--- 1605,1617 ----
      char_u    *ptr,           // file name
      int               len,            // length of file name
      int               options,
!     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 *)"",
!                                      file_to_find, search_ctx);
  }
  
      char_u *
***************
*** 1622,1629 ****
      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
  {
      static char_u     *dir;
      static int                did_findfile_init = FALSE;
      char_u            save_char;
--- 1623,1633 ----
      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    **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,1657 ****
        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
        {
            file_name = NULL;
            goto theend;
--- 1653,1661 ----
        expand_env_esc(ptr, NameBuff, MAXPATHL, FALSE, TRUE, NULL);
        ptr[len] = save_char;
  
!       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,1688 ****
        if (options & FNAME_UNESC)
        {
            // Change all "\ " to " ".
!           for (ptr = ff_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)
            // "..", "../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])
            // handle "c:name" as absolute path
!           || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':')
  # endif
  # ifdef AMIGA
            // handle ":tmp" as absolute path
!           || ff_file_to_find[0] == ':'
  # endif
         )
      {
--- 1663,1692 ----
        if (options & FNAME_UNESC)
        {
            // Change all "\ " to " ".
!           for (ptr = *file_to_find; *ptr != NUL; ++ptr)
                if (ptr[0] == '\\' && ptr[1] == ' ')
                    mch_memmove(ptr, ptr + 1, STRLEN(ptr));
        }
      }
  
!     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((*file_to_find)[0])
            // handle "c:name" as absolute path
!           || ((*file_to_find)[0] != NUL && (*file_to_find)[1] == ':')
  # endif
  # ifdef AMIGA
            // handle ":tmp" as absolute path
!           || (*file_to_find)[0] == ':'
  # endif
         )
      {
***************
*** 1696,1704 ****
            int         l;
            int         run;
  
!           if (path_with_url(ff_file_to_find))
            {
!               file_name = vim_strsave(ff_file_to_find);
                goto theend;
            }
  
--- 1700,1708 ----
            int         l;
            int         run;
  
!           if (path_with_url(*file_to_find))
            {
!               file_name = vim_strsave(*file_to_find);
                goto theend;
            }
  
***************
*** 1706,1712 ****
            // Otherwise or when this fails use the current directory.
            for (run = 1; run <= 2; ++run)
            {
!               l = (int)STRLEN(ff_file_to_find);
                if (run == 1
                        && rel_to_curdir
                        && (options & FNAME_REL)
--- 1710,1716 ----
            // Otherwise or when this fails use the current directory.
            for (run = 1; run <= 2; ++run)
            {
!               l = (int)STRLEN(*file_to_find);
                if (run == 1
                        && rel_to_curdir
                        && (options & FNAME_REL)
***************
*** 1714,1725 ****
                        && STRLEN(rel_fname) + l < MAXPATHL)
                {
                    STRCPY(NameBuff, rel_fname);
!                   STRCPY(gettail(NameBuff), ff_file_to_find);
                    l = (int)STRLEN(NameBuff);
                }
                else
                {
!                   STRCPY(NameBuff, ff_file_to_find);
                    run = 2;
                }
  
--- 1718,1729 ----
                        && STRLEN(rel_fname) + l < MAXPATHL)
                {
                    STRCPY(NameBuff, rel_fname);
!                   STRCPY(gettail(NameBuff), *file_to_find);
                    l = (int)STRLEN(NameBuff);
                }
                else
                {
!                   STRCPY(NameBuff, *file_to_find);
                    run = 2;
                }
  
***************
*** 1753,1759 ****
        if (first == TRUE)
        {
            // vim_findfile_free_visited can handle a possible NULL pointer
!           vim_findfile_free_visited(fdip_search_ctx);
            dir = path_option;
            did_findfile_init = FALSE;
        }
--- 1757,1763 ----
        if (first == TRUE)
        {
            // vim_findfile_free_visited can handle a possible NULL pointer
!           vim_findfile_free_visited(*search_ctx);
            dir = path_option;
            did_findfile_init = FALSE;
        }
***************
*** 1762,1768 ****
        {
            if (did_findfile_init)
            {
!               file_name = vim_findfile(fdip_search_ctx);
                if (file_name != NULL)
                    break;
  
--- 1766,1772 ----
        {
            if (did_findfile_init)
            {
!               file_name = vim_findfile(*search_ctx);
                if (file_name != NULL)
                    break;
  
***************
*** 1776,1783 ****
                {
                    // We searched all paths of the option, now we can
                    // free the search context.
!                   vim_findfile_cleanup(fdip_search_ctx);
!                   fdip_search_ctx = NULL;
                    break;
                }
  
--- 1780,1787 ----
                {
                    // We searched all paths of the option, now we can
                    // free the search context.
!                   vim_findfile_cleanup(*search_ctx);
!                   *search_ctx = NULL;
                    break;
                }
  
***************
*** 1790,1799 ****
  
                // get the stopdir string
                r_ptr = vim_findfile_stopdir(buf);
!               fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find,
                                            r_ptr, 100, FALSE, find_what,
!                                          fdip_search_ctx, FALSE, rel_fname);
!               if (fdip_search_ctx != NULL)
                    did_findfile_init = TRUE;
                vim_free(buf);
            }
--- 1794,1803 ----
  
                // get the stopdir string
                r_ptr = vim_findfile_stopdir(buf);
!               *search_ctx = vim_findfile_init(buf, *file_to_find,
                                            r_ptr, 100, FALSE, find_what,
!                                          *search_ctx, FALSE, rel_fname);
!               if (*search_ctx != NULL)
                    did_findfile_init = TRUE;
                vim_free(buf);
            }
***************
*** 1804,1823 ****
        if (first == TRUE)
        {
            if (find_what == FINDFILE_DIR)
!               semsg(_(e_cant_find_directory_str_in_cdpath),
!                       ff_file_to_find);
            else
!               semsg(_(e_cant_find_file_str_in_path),
!                       ff_file_to_find);
        }
        else
        {
            if (find_what == FINDFILE_DIR)
                semsg(_(e_no_more_directory_str_found_in_cdpath),
!                       ff_file_to_find);
            else
!               semsg(_(e_no_more_file_str_found_in_path),
!                       ff_file_to_find);
        }
      }
  
--- 1808,1824 ----
        if (first == TRUE)
        {
            if (find_what == FINDFILE_DIR)
!               semsg(_(e_cant_find_directory_str_in_cdpath), *file_to_find);
            else
!               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),
!                                                               *file_to_find);
            else
!               semsg(_(e_no_more_file_str_found_in_path), *file_to_find);
        }
      }
  
***************
*** 2046,2053 ****
  
      if (options & FNAME_EXP)
      {
        file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
!                                                            TRUE, rel_fname);
  
  # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
        /*
--- 2047,2057 ----
  
      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, &file_to_find, &search_ctx);
  
  # if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
        /*
***************
*** 2063,2069 ****
                ptr = tofree;
                len = (int)STRLEN(ptr);
                file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
!                                                            TRUE, rel_fname);
            }
        }
  # endif
--- 2067,2073 ----
                ptr = tofree;
                len = (int)STRLEN(ptr);
                file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
!                                 TRUE, rel_fname, &file_to_find, &search_ctx);
            }
        }
  # endif
***************
*** 2080,2087 ****
        while (file_name != NULL && --count > 0)
        {
            vim_free(file_name);
!           file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
        }
      }
      else
        file_name = vim_strnsave(ptr, len);
--- 2084,2095 ----
        while (file_name != NULL && --count > 0)
        {
            vim_free(file_name);
!           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);
*** ../vim-9.0.1399/src/proto/findfile.pro      2022-06-27 23:15:06.000000000 
+0100
--- src/proto/findfile.pro      2023-03-11 13:23:46.163820544 +0000
***************
*** 3,12 ****
  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);
  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 *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);
--- 3,12 ----
  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 **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 **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);
*** ../vim-9.0.1399/src/filepath.c      2023-01-22 18:38:45.498261340 +0000
--- src/filepath.c      2023-03-11 13:18:31.812031442 +0000
***************
*** 982,987 ****
--- 982,990 ----
  
      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,1004 ****
                                        find_what,
                                        curbuf->b_ffname,
                                        find_what == FINDFILE_DIR
!                                           ? (char_u *)"" : curbuf->b_p_sua);
            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);
      }
  
      if (rettv->v_type == VAR_STRING)
--- 995,1011 ----
                                        find_what,
                                        curbuf->b_ffname,
                                        find_what == FINDFILE_DIR
!                                           ? (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)
*** ../vim-9.0.1399/src/ex_docmd.c      2023-02-21 14:27:34.516360384 +0000
--- src/ex_docmd.c      2023-03-11 13:22:11.687866787 +0000
***************
*** 6767,6774 ****
  
      if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind)
      {
        fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
!                                         FNAME_MESS, TRUE, curbuf->b_ffname);
        if (fname == NULL)
            goto theend;
        eap->arg = fname;
--- 6767,6779 ----
  
      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,
!                                         &file_to_find, &search_ctx);
!       vim_free(file_to_find);
!       vim_findfile_cleanup(search_ctx);
        if (fname == NULL)
            goto theend;
        eap->arg = fname;
***************
*** 7032,7052 ****
  {
      char_u    *fname;
      int               count;
  
      fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS,
!                                                     TRUE, curbuf->b_ffname);
      if (eap->addr_count > 0)
      {
!       // 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);
        }
      }
  
      if (fname == NULL)
        return;
--- 7037,7061 ----
  {
      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, &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.
        count = eap->line2;
        while (fname != NULL && --count > 0)
        {
            vim_free(fname);
            fname = find_file_in_path(NULL, 0, FNAME_MESS,
!                         FALSE, curbuf->b_ffname, &file_to_find, &search_ctx);
        }
      }
+     VIM_CLEAR(file_to_find);
+     vim_findfile_cleanup(search_ctx);
  
      if (fname == NULL)
        return;
***************
*** 7057,7063 ****
  }
  
  /*
!  * ":open" simulation: for now just work like ":visual".
   */
      static void
  ex_open(exarg_T *eap)
--- 7066,7072 ----
  }
  
  /*
!  * ":open" simulation: for now works just like ":visual".
   */
      static void
  ex_open(exarg_T *eap)
***************
*** 7138,7150 ****
            // 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);
--- 7147,7152 ----
***************
*** 7153,7163 ****
--- 7155,7169 ----
  
                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,7176 ****
                main_loop(FALSE, TRUE);
  
                pending_exmode_active = FALSE;
!               RedrawingDisabled = rd;
!               no_wait_return = nwr;
!               msg_scroll = ms;
  #ifdef FEAT_GUI
!               hold_gui_events = he;
  #endif
            }
            return;
--- 7172,7182 ----
                main_loop(FALSE, TRUE);
  
                pending_exmode_active = FALSE;
!               RedrawingDisabled = save_rd;
!               no_wait_return = save_nwr;
!               msg_scroll = save_ms;
  #ifdef FEAT_GUI
!               hold_gui_events = save_he;
  #endif
            }
            return;
*** ../vim-9.0.1399/src/misc2.c 2023-03-04 20:47:32.304617857 +0000
--- src/misc2.c 2023-03-11 13:20:09.495946931 +0000
***************
*** 2473,2481 ****
  {
      char_u    *dir_name;
      int               r;
  
      dir_name = find_directory_in_path(new_dir, (int)STRLEN(new_dir),
!                                               FNAME_MESS, curbuf->b_ffname);
      if (dir_name == NULL)
        return -1;
      r = mch_chdir((char *)dir_name);
--- 2473,2485 ----
  {
      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, &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);
*** ../vim-9.0.1399/src/version.c       2023-03-10 18:36:47.384425094 +0000
--- src/version.c       2023-03-11 13:51:01.159809854 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1400,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
262. Your computer has it's own phone line - but your daughter doesn't.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230311135637.0D2DB1C0D07%40moolenaar.net.

Raspunde prin e-mail lui