]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
changes for PATH being the empty string; more minor asan fixes
authorChet Ramey <chet.ramey@case.edu>
Fri, 17 Mar 2023 20:03:11 +0000 (16:03 -0400)
committerChet Ramey <chet.ramey@case.edu>
Fri, 17 Mar 2023 20:03:11 +0000 (16:03 -0400)
CWRU/CWRU.chlog
bashline.c
builtins/cd.def
builtins/enable.def
config-top.h
findcmd.c
findcmd.h
parse.y
tests/exec.right
tests/execscript

index a0c7cb260b2faa7cf7c07b9b40070ee29b93c831..54b55a501e47ea11ac5efc654ed336a5c1141112 100644 (file)
@@ -5661,3 +5661,49 @@ doc/{bash.1,bashref.texi}
 doc/bash.1,lib/readline/doc/rluser.texi
        - shell-expand-line: enumerate the specific expansions performed.
          From a request by Alex Bochannek <alex@bochannek.com>
+
+findcmd.c
+       - path_value: new function, returns normalized version of $PATH. Takes
+         a single argument saying whether or not to look in the temporary
+         environment first. Normalizes null $PATH (PATH=) into ".". From a
+         bug-bash discussion started by Moshe Looks <moshe.looks@gmail.com>
+       - _find_user_command_in_path: use path_value()
+       - user_command_matches: use path_value()
+       - search_for_command: if PATH[0] == 0, set PATH = "." like path_value().
+         This has the side effect of calling command_not_found_handle when
+         PATH is the empty string and the command isn't in the current
+         directory
+       - search_for_command: if path == 0, but we found an executable in the
+         current directory, make sure to set dot_found_in_search before adding
+         it to the command hash table
+
+findcmd.h
+       - path_value: extern declaration
+
+bashline.c
+       - command_word_completion_function: use path_value()
+
+builtins/enable.def
+       - dyn_load_builtin: use path_value for BASH_LOADABLES_PATH; it's cleaner
+         though it doesn't change the behavior
+
+                                  3/17
+                                  ----
+bashline.c 
+       - bashline_reset: reset rl_filename_quoting_function, since there is a
+         SIGINT code path where it could remain reset by glob completion.
+         Reported by Grisha Levit <grishalevit@gmail.com>
+       - command_word_completion_function,command_subst_completion_function,
+         glob_complete_word: set some static variables to NULL
+         after freeing them so they don't potentially get freed twice after
+         a SIGINT during completion
+         Reported by Grisha Levit <grishalevit@gmail.com>
+
+parse.y
+       - read_token_word: when deciding how to quote translated strings, don't
+         free ttok before comparing it to ttrans
+         Reported by Grisha Levit <grishalevit@gmail.com>
+       - parse_matched_pair: same thing for freeing nestret
+       - read_token: if we return a newline, make sure we call set_word_top()
+         if necessary.
+         Fixes underflow reported by Grisha Levit <grishalevit@gmail.com>
index 2745c4dd135d38e4ad70733f3b9675d0faa484b9..0047caeffe6fc762b0cb5cf12f342eb13f7fe1e9 100644 (file)
@@ -686,6 +686,8 @@ bashline_reset (void)
   rl_filename_quote_characters = default_filename_quote_characters;
   set_filename_bstab (rl_filename_quote_characters);
 
+  rl_filename_quoting_function = bash_quote_filename;
+
   set_directory_hook ();
   rl_filename_stat_hook = bash_filename_stat_hook;
 
@@ -1922,12 +1924,8 @@ executable_completion (const char *filename, int searching_path)
 
   /* This gets an unquoted filename, so we need to quote special characters
      in the filename before the completion hook gets it. */
-#if 0
-  f = savestring (filename);
-#else
   c = 0;
   f = bash_quote_filename ((char *)filename, SINGLE_MATCH, &c);
-#endif
   bash_directory_completion_hook (&f);
   
   r = searching_path ? executable_file (f) : executable_or_directory (f);
@@ -1970,6 +1968,7 @@ command_word_completion_function (const char *hint_text, int state)
        free (dequoted_hint);
       if (hint)
        free (hint);
+      dequoted_hint = hint = (char *)NULL;
 
       mapping_over = searching_path = 0;
       hint_is_dir = CMD_IS_DIR (hint_text);
@@ -2064,7 +2063,7 @@ command_word_completion_function (const char *hint_text, int state)
       if (rl_completion_found_quote && rl_completion_quote_character == 0)
        dequoted_hint = bash_dequote_filename (hint, 0);
       
-      path = get_string_value ("PATH");
+      path = path_value ("PATH", 0);
       path_index = dot_in_path = 0;
 
       /* Initialize the variables for each type of command word. */
@@ -2252,6 +2251,7 @@ globword:
        free (fnhint);
       if (filename_hint)
        free (filename_hint);
+      fnhint = filename_hint = (char *)NULL;
 
       filename_hint = sh_makepath (current_path, hint, 0);
       /* Need a quoted version (though it doesn't matter much in most
@@ -2347,6 +2347,7 @@ globword:
          t1 = make_absolute (val, t);
          free (t);
          cval = sh_canonpath (t1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+         free (t1);
        }
       else
 #endif
@@ -2397,7 +2398,10 @@ command_subst_completion_function (const char *text, int state)
       start_len = text - orig_start;
       filename_text = savestring (text);
       if (matches)
-       free (matches);
+       {
+         free (matches);
+         matches = (char **)NULL;
+       }
 
       /*
        * At this point we can entertain the idea of re-parsing
@@ -3873,9 +3877,11 @@ glob_complete_word (const char *text, int state)
     {
       rl_filename_completion_desired = 1;
       FREE (matches);
+      matches = (char **)NULL;
       if (globorig != globtext)
        FREE (globorig);
       FREE (globtext);
+      globorig = globtext = (char *)NULL;
 
       ttext = bash_tilde_expand (text, 0);
 
index 08f18da9ea73f57e12baf96e9e16b1f303ba9627..35d95f67cbed3dcb00f7196e1c72834bdf9d7e2a 100644 (file)
@@ -1,7 +1,7 @@
 This file is cd.def, from which is created cd.c.  It implements the
 builtins "cd" and "pwd" in Bash.
 
-Copyright (C) 1987-2022 Free Software Foundation, Inc.
+Copyright (C) 1987-2023 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -390,20 +390,6 @@ cd_builtin (WORD_LIST *list)
          else
            free (temp);
        }
-
-#if 0
-      /* changed for bash-4.2 Posix cd description steps 5-6 */
-      /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
-        try the current directory, so we just punt now with an error
-        message if POSIXLY_CORRECT is non-zero.  The check for cdpath[0]
-        is so we don't mistakenly treat a CDPATH value of "" as not
-        specifying the current directory. */
-      if (posixly_correct && cdpath[0])
-       {
-         builtin_error ("%s: %s", dirname, strerror (ENOENT));
-         return (EXECUTION_FAILURE);
-       }
-#endif
     }
   else
     dirname = list->word->word;
index b6d6a8fe244e47ec5de1522f4cd8d2eaef135d3a..e6948bac56c023c178797bba2009cd3d3f357493 100644 (file)
@@ -336,7 +336,7 @@ dyn_load_builtin (WORD_LIST *list, int flags, char *filename)
   handle = 0;
   if (absolute_program (filename) == 0)
     {
-      loadables_path = get_string_value ("BASH_LOADABLES_PATH");
+      loadables_path = path_value ("BASH_LOADABLES_PATH", 1);
       if (loadables_path)
        {
          load_path = find_in_path (filename, loadables_path, FS_NODIRS|FS_EXEC_PREFERRED);
index 5a3227062b5de5c92996480f3382621ec1d383d6..6e87a7cedaed19ca56114fa95fc88f8e0fe2248d 100644 (file)
 
 /* Define as 1 if you want to enable code that implements multiple coprocs
    executing simultaneously */
+/* TAG: bash-5.3 */
 #ifndef MULTIPLE_COPROCS
 #  define MULTIPLE_COPROCS 0
 #endif
index 186871ace6f3993b21135bb8c1d5935af931025f..bbb8ae928dc9ad911ae3dcc0f626ca2d12429d61 100644 (file)
--- a/findcmd.c
+++ b/findcmd.c
@@ -248,6 +248,23 @@ find_path_file (const char *name)
   return (find_user_command_internal (name, FS_READABLE));
 }
 
+/* Get $PATH and normalize it. USE_TEMPENV, if non-zero, says to look in the
+   temporary environment first. Normalizing means converting PATH= into ".". */
+char *
+path_value (const char *pathvar, int use_tempenv)
+{
+  SHELL_VAR *var;
+  char *path;
+
+  var = use_tempenv ? find_variable_tempenv (pathvar) : find_variable (pathvar);
+  path = var ? value_cell (var) : (char *)NULL;
+
+  if (path == 0 || *path)
+    return (path);
+  else         /* *path == '\0' */
+    return ".";
+}
+
 static char *
 _find_user_command_internal (const char *name, int flags)
 {
@@ -256,12 +273,9 @@ _find_user_command_internal (const char *name, int flags)
 
   /* Search for the value of PATH in both the temporary environments and
      in the regular list of variables. */
-  if (var = find_variable_tempenv ("PATH"))    /* XXX could be array? */
-    path_list = value_cell (var);
-  else
-    path_list = (char *)NULL;
+  path_list = path_value ("PATH", 1);
 
-  if (path_list == 0 || *path_list == '\0')
+  if (path_list == 0)
     return (savestring (name));
 
   cmd = find_user_command_in_path (name, path_list, flags, (int *)0);
@@ -364,7 +378,11 @@ search_for_command (const char *pathname, int flags)
       if (flags & CMDSRCH_STDPATH)
        path_list = conf_standard_path ();
       else if (temp_path || path)
-       path_list = value_cell (path);
+       {
+         path_list = value_cell (path);
+         if (path_list && *path_list == '\0')
+           path_list = ".";
+       }
       else
        path_list = 0;
 
@@ -377,6 +395,11 @@ search_for_command (const char *pathname, int flags)
             table unless it's an executable file in the current directory. */
          if (STREQ (command, pathname))
            {
+             if (path_list == 0)
+               {
+                 dot_found_in_search = 1;
+                 st = file_status (pathname);
+               }
              if (st & FS_EXECABLE)
                phash_insert ((char *)pathname, command, dot_found_in_search, 1);
            }
@@ -439,8 +462,8 @@ user_command_matches (const char *name, int flags, int state)
          dot_found_in_search = 0;
          if (stat (".", &dotinfo) < 0)
            dotinfo.st_dev = dotinfo.st_ino = 0;        /* so same_file won't match */
-         path_list = get_string_value ("PATH");
-         path_index = 0;
+         path_list = path_value ("PATH", 0);
+         path_index = 0;
        }
 
       while (path_list && path_list[path_index])
@@ -573,7 +596,9 @@ find_in_path_element (const char *name, char *path, int flags, size_t name_len,
 /* This does the dirty work for find_user_command_internal () and
    user_command_matches ().
    NAME is the name of the file to search for.
-   PATH_LIST is a colon separated list of directories to search.
+   PATH_LIST is a colon separated list of directories to search. It is the
+   caller's responsibility to pass a non-empty path if they want an empty
+   path to be treated specially.
    FLAGS contains bit fields which control the files which are eligible.
    Some values are:
       FS_EXEC_ONLY:            The file must be an executable to be found.
index b0d80d11319145f3613d702d0c862a255975e20a..6dbded4c11b3199bff76afba231c831eee2769dc 100644 (file)
--- a/findcmd.h
+++ b/findcmd.h
@@ -35,6 +35,7 @@ extern int executable_or_directory (const char *);
 extern char *find_user_command (const char *);
 extern char *find_in_path (const char *, char *, int);
 extern char *find_path_file (const char *);
+extern char *path_value (const char *, int);
 extern char *search_for_command (const char *, int);
 extern char *user_command_matches (const char *, int, int);
 extern void setup_exec_ignore (const char *);
diff --git a/parse.y b/parse.y
index e3516e2d2009dc4552aeba36eb9894c62d9d4f0c..33a4ddfd9ff90824ff89ae8faa8f7a722593e1e8 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -3470,6 +3470,9 @@ read_token (int command)
       parser_state &= ~PST_ASSIGNOK;
       parser_state &= ~PST_CMDBLTIN;
 
+      if (last_read_token == IF || last_read_token == WHILE || last_read_token == UNTIL)
+       set_word_top (last_read_token);
+
       return (character);
     }
 
@@ -3906,7 +3909,6 @@ parse_matched_pair (int qc, int open, int close, size_t *lenp, int flags)
                  /* Locale expand $"..." here. */
                  /* PST_NOEXPAND */
                  ttrans = locale_expand (nestret, 0, nestlen - 1, start_lineno, &ttranslen);
-                 free (nestret);
 
                  /* If we're supposed to single-quote translated strings,
                     check whether the translated result is different from
@@ -3914,6 +3916,7 @@ parse_matched_pair (int qc, int open, int close, size_t *lenp, int flags)
                  if (singlequote_translations &&
                        ((nestlen - 1) != ttranslen || STREQN (nestret, ttrans, ttranslen) == 0))
                    {
+                     free (nestret);
                      if ((rflags & P_DQUOTE) == 0)
                        nestret = sh_single_quote (ttrans);
                      else if ((rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2) && (flags & P_DOLBRACE))
@@ -3923,7 +3926,10 @@ parse_matched_pair (int qc, int open, int close, size_t *lenp, int flags)
                        nestret = sh_backslash_quote_for_double_quotes (ttrans, 0);
                    }
                  else
-                   nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
+                   {
+                     free (nestret);
+                     nestret = sh_mkdoublequoted (ttrans, ttranslen, 0);
+                   }
                  free (ttrans);
                  nestlen = strlen (nestret);
                  retind -= 2;          /* back up before the $" */
@@ -5228,15 +5234,20 @@ read_token_word (int character)
                  /* PST_NOEXPAND */
                  /* Try to locale-expand the converted string. */
                  ttrans = locale_expand (ttok, 0, ttoklen - 1, first_line, &ttranslen);
-                 free (ttok);
 
                  /* Add the double quotes back (or single quotes if the user
                     has set that option). */
                  if (singlequote_translations &&
                        ((ttoklen - 1) != ttranslen || STREQN (ttok, ttrans, ttranslen) == 0))
-                   ttok = sh_single_quote (ttrans);
+                   {
+                     free (ttok);
+                     ttok = sh_single_quote (ttrans);
+                   }
                  else
-                   ttok = sh_mkdoublequoted (ttrans, ttranslen, 0);
+                   {
+                     free (ttok);
+                     ttok = sh_mkdoublequoted (ttrans, ttranslen, 0);
+                   }
 
                  free (ttrans);
                  ttrans = ttok;
index f7e8a7fbd208e22806f7f401b1653f4db4c60b70..09204f1b2d942f494335214a0475efa53c350fad 100644 (file)
@@ -31,11 +31,17 @@ trap -- '' SIGTERM
 trap -- 'echo USR1' SIGUSR1
 USR1
 EXIT
-./execscript: line 71: notthere: No such file or directory
+./execscript: line 71: notthere: command not found
 127
-./execscript: line 74: notthere: No such file or directory
+./execscript: line 73: notthere: command not found
 127
-./execscript: line 77: notthere: command not found
+./execscript: line 75: notthere: command not found
+127
+./execscript: line 81: notthere: command not found
+127
+./execscript: line 83: notthere: command not found
+127
+./execscript: line 85: notthere: command not found
 127
 this is sh
 this is sh
index 706c1e13efba2840d49269216f0f19f6cbf2b3b2..f8ecf1edf2d4a8bc4347ca05189a4f462efa07f2 100644 (file)
@@ -65,15 +65,23 @@ ${THIS_SH} ./exec3.sub
 rm -f $TMPDIR/bashenv
 unset BASH_ENV
 
+# these results should be the same as with an empty PATH
+PATH=.
+
+notthere
+echo $?
+command notthere
+echo $?
+command -p notthere
+echo $?
+
 # we're resetting the $PATH to empty, so this should be last
 PATH=
 
 notthere
 echo $?
-
 command notthere
 echo $?
-
 command -p notthere
 echo $?