- shell_execve: fix typo in code that chops \r off the end of the #!
interpreter
Report and fix from Collin Funk <collin.funk1@gmail.com>
+
+ 5/28
+ ----
+execute_cmd.c
+ - time_command: only restore command->flags if we haven't longjmped
+ Report from Michael Maurer <michael.maurer@univie.ac.at> and
+ Grisha Levit <grishalevit@gmail.com>
+
+subst.c
+ - skip_to_delim: if we're not skipping over command substitutions
+ lexically, call extract_command_subst instead of using the old
+ extract_delimited_string
+ Fixes bug reported by Oguz <oguzismailuysal@gmail.com>
+
+execute_cmd.c
+ - execute_arith_for_command: handle the extremely unlikely case that
+ the step or test expressions execute `break' or `continue' in a
+ nofork command substitution
+ Report from Oguz <oguzismailuysal@gmail.com>
+
+ 5/29
+ ----
+lib/readline/complete.c
+ - compute_lcd_of_matches: if we have multiple matches that compare
+ equally when using case-insensitive completion, but are different
+ lengths due to the presence of multibyte characters, use the
+ shorter match as the common prefix to avoid overflow
+ Report from Grisha Levit <grishalevit@gmail.com>
+
+ 5/30
+ ----
+lib/readline/text.c
+ - _rl_readstr_init: don't call rl_maybe_replace_line since we're not
+ actually moving off this history line
+ Report from Grisha Levit <grishalevit@gmail.com>
+
+builtins/read.def
+ - read_builtin: free ifs_chars in more return code paths
+ Report and patch from Grisha Levit <grishalevit@gmail.com>
+
+ 5/31
+ ----
+quit.h
+ - ZRESET: new macro, calls zreset() if interrupt_state is non-zero
+
+lib/sh/zread.c
+ - zread: if read returns -1/EINTR, and we're executing a builtin,
+ call zreset just in case
+
+builtins/read.def
+ - read_builtin: if read returns > 0 (partial read) but interrupt_state
+ is non-zero, we're going to call throw_to_top_level, so call
+ ZRESET before that happens
+ Report from Oguz <oguzismailuysal@gmail.com>
+ - read_builtin: if zread/zreadc/zreadintr/zreadcintr return -1/EINTR,
+ make sure we call ZRESET in case zread did not
+
+variables.h
+ - ASSIGN_DISALLOWED: macro that encapsulates when an assignment to
+ SHELL_VAR *v with flags f will be disallowed and fail
+
+arrayfunc.c,execute_cmd.c,expr.c,redir.c,subst.c,variables.c
+builtins/delare.def,builtins/getopts.def,builtins/printf.def,builtins/read.def
+ - use ASSIGN_DISALLOWED where appropriate
+
+arrayfunc.c
+ - assign_array_element_internal: if the assignment failed, as tested by
+ ASSIGN_DISALLOWED, free the assoc array key we allocated
+ Report from Grisha Levit <grishalevit@gmail.com>
}
if (entry == (SHELL_VAR *) 0)
entry = make_new_array_variable (name);
- else if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
+ else if (ASSIGN_DISALLOWED (entry, flags))
{
if (readonly_p (entry))
err_readonly (name);
SHELL_VAR *
bind_assoc_variable (SHELL_VAR *entry, const char *name, char *key, const char *value, int flags)
{
- if ((readonly_p (entry) && (flags&ASS_FORCE) == 0) || noassign_p (entry))
+ if (ASSIGN_DISALLOWED (entry, flags))
{
if (readonly_p (entry))
err_readonly (name);
if (estatep)
nkey = savestring (akey); /* assoc_insert/assoc_replace frees akey */
entry = bind_assoc_variable (entry, vname, akey, value, flags);
+ /* If we didn't perform the assignment, free the key we allocated */
+ if (entry == 0 || (ASSIGN_DISALLOWED (entry, flags)))
+ FREE (akey);
if (estatep)
{
estatep->type = ARRAY_ASSOC;
if (var == 0)
var = (flags & 2) ? make_new_assoc_variable (name) : make_new_array_variable (name);
- else if ((flags & 1) && (readonly_p (var) || noassign_p (var)))
+ else if ((flags & 1) && ASSIGN_DISALLOWED(var, 0))
{
if (readonly_p (var))
err_readonly (name);
NEXT_VARIABLE ();
}
/* Cannot use declare to assign value to readonly or noassign variable. */
- else if ((readonly_p (var) || noassign_p (var)) && offset)
+ else if (ASSIGN_DISALLOWED (var, 0) && offset)
{
if (readonly_p (var))
{
if (valid_identifier (name))
{
v = bind_variable (name, value, 0);
- if (v && (readonly_p (v) || noassign_p (v)))
+ if (v && ASSIGN_DISALLOWED (v, 0))
return (EX_MISCERROR);
return (v ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
SHELL_VAR *v; \
v = builtin_bind_variable (vname, vbuf, bindflags); \
stupidly_hack_special_variables (vname); \
- if (v == 0 || readonly_p (v) || noassign_p (v)) \
+ if (v == 0 || ASSIGN_DISALLOWED (v, 0)) \
retval = EXECUTION_FAILURE; \
if (vbsize > 4096) \
{ \
SHELL_VAR *v;
v = builtin_bind_variable (vname, "", 0);
stupidly_hack_special_variables (vname);
- return ((v == 0 || readonly_p (v) || noassign_p (v)) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+ return ((v == 0 || ASSIGN_DISALLOWED (v, 0)) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
/* If the format string is empty after preprocessing, return immediately. */
if (fd2 >= 0)
close (fd2);
run_unwind_frame ("read_builtin");
+ if (free_ifs)
+ free (ifs_chars);
return (EXECUTION_FAILURE);
}
x = errno;
if (retval < 0 && errno == EINTR)
{
+ ZRESET ();
check_signals (); /* in case we didn't call zread via zreadc */
lastsig = LASTSIG();
if (lastsig == 0)
break;
}
+ /* Even if read returns a partial buffer, if we got an interrupt we're
+ going to throw it away. */
+ ZRESET();
+
QUIT; /* in case we didn't call check_signals() */
#if defined (READLINE)
}
if (errno != EINTR)
builtin_error ("%d: %s: %s", fd, _("read error"), strerror (errno));
run_unwind_frame ("read_builtin");
+ if (free_ifs)
+ free (ifs_chars);
return ((t_errno != EINTR) ? EXECUTION_FAILURE : 128+lastsig);
}
if (var == 0)
{
free (input_string);
+ if (free_ifs)
+ free (ifs_chars);
return EXECUTION_FAILURE; /* readonly or noassign */
}
dispose_words (alist);
}
free (input_string);
+ if (free_ifs)
+ free (ifs_chars);
return (retval);
}
#endif /* ARRAY_VARS */
}
else
var = bind_variable ("REPLY", input_string, 0);
- if (var == 0 || readonly_p (var) || noassign_p (var))
+ if (var == 0 || ASSIGN_DISALLOWED (var, 0))
retval = EX_MISCERROR;
else
VUNSETATTR (var, att_invisible);
free (input_string);
+ if (free_ifs)
+ free (ifs_chars);
return (retval);
}
{
sh_invalidid (varname);
free (orig_input_string);
+ if (free_ifs)
+ free (ifs_chars);
return (EXECUTION_FAILURE);
}
if (var == 0)
{
free (orig_input_string);
+ if (free_ifs)
+ free (ifs_chars);
return (EX_MISCERROR);
}
{
sh_invalidid (list->word->word);
free (orig_input_string);
+ if (free_ifs)
+ free (ifs_chars);
return (EXECUTION_FAILURE);
}
SHELL_VAR *v;
v = builtin_bind_variable (name, value, flags);
- return (v == 0 ? v
- : ((readonly_p (v) || noassign_p (v)) ? (SHELL_VAR *)NULL : v));
+ return ((v == 0 || ASSIGN_DISALLOWED (v, 0)) ? (SHELL_VAR *)NULL : v);
}
#if defined (HANDLE_MULTIBYTE)
/* Define if you have the tcgetpgrp function. */
#undef HAVE_TCGETPGRP
+/* Define if you have the tcgetwinsize function. */
+#undef HAVE_TCGETWINSIZE
+
+/* Define if you have the tcsetwinsize function. */
+#undef HAVE_SETWINSIZE
+
/* Define if you have the times function. */
#undef HAVE_TIMES
#! /bin/sh
-# From configure.ac for Bash 5.3, version 5.064.
+# From configure.ac for Bash 5.3, version 5.065.
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.72 for bash 5.3-alpha.
#
then :
printf "%s\n" "#define HAVE_TCGETATTR 1" >>confdefs.h
+fi
+ac_fn_c_check_func "$LINENO" "tcgetwinsize" "ac_cv_func_tcgetwinsize"
+if test "x$ac_cv_func_tcgetwinsize" = xyes
+then :
+ printf "%s\n" "#define HAVE_TCGETWINSIZE 1" >>confdefs.h
+
+fi
+ac_fn_c_check_func "$LINENO" "tcsetwinsize" "ac_cv_func_tcsetwinsize"
+if test "x$ac_cv_func_tcsetwinsize" = xyes
+then :
+ printf "%s\n" "#define HAVE_TCSETWINSIZE 1" >>confdefs.h
+
fi
ac_fn_c_check_func "$LINENO" "times" "ac_cv_func_times"
if test "x$ac_cv_func_times" = xyes
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-AC_REVISION([for Bash 5.3, version 5.064])dnl
+AC_REVISION([for Bash 5.3, version 5.065])dnl
define(bashvers, 5.3)
define(relstatus, alpha)
getaddrinfo gethostbyname getservbyname getservent inet_aton \
imaxdiv memmove pathconf putenv raise random regcomp regexec \
setenv setlinebuf setlocale setvbuf siginterrupt strchr \
- sysconf syslog tcgetattr times ttyname tzset unsetenv)
+ sysconf syslog tcgetattr tcgetwinsize tcsetwinsize \
+ times ttyname tzset unsetenv)
AC_CHECK_FUNCS(vasprintf asprintf)
AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit)
rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close);
COPY_PROCENV (save_top_level, top_level);
- command->flags = old_flags;
+ if (code == NOT_JUMPED)
+ command->flags = old_flags;
/* If we're jumping in a different subshell environment than we started,
don't bother printing timing stats, just keep longjmping back to the
}
}
- if (v && (readonly_p (v) || noassign_p (v)))
+ if (v && ASSIGN_DISALLOWED (v, 0))
{
if (readonly_p (v))
err_readonly (cp->c_name);
else
v = bind_variable (identifier, list->word->word, 0);
- if (v == 0 || readonly_p (v) || noassign_p (v))
+ if (v == 0 || ASSIGN_DISALLOWED (v, 0))
{
line_number = save_line_number;
if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct)
expresult = eval_arith_for_expr (arith_for_command->test, &expok);
line_number = save_lineno;
+ /* If the step or test expressions execute `break' or `continue' in a
+ nofork command substitution or by some other means, break the loop
+ here. */
+ if (breaking)
+ {
+ breaking--;
+ break;
+ }
+ if (continuing)
+ {
+ continuing--;
+ if (continuing)
+ break;
+ }
+
if (expok == 0)
break;
}
v = bind_variable (identifier, selection, 0);
- if (v == 0 || readonly_p (v) || noassign_p (v))
+ if (v == 0 || ASSIGN_DISALLOWED (v, 0))
{
if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct)
{
}
var = find_function (name->word);
- if (var && (readonly_p (var) || noassign_p (var)))
+ if (var && ASSIGN_DISALLOWED (var, 0))
{
if (readonly_p (var))
internal_error (_("%s: readonly function"), var->name);
aflags = 0;
#endif
v = bind_int_variable (lhs, rhs, aflags);
- if (v && (readonly_p (v) || noassign_p (v)))
+ if (v && ASSIGN_DISALLOWED (v, 0))
sh_longjmp (evalbuf, 1); /* variable assignment error */
stupidly_hack_special_variables (lhs);
}
# include "colors.h"
#endif
+#ifndef MIN
+#define MIN(x,y) (((x) < (y)) ? (x): (y))
+#endif
+
typedef int QSFUNC (const void *, const void *);
#ifdef HAVE_LSTAT
int low; /* Count of max-matched characters. */
int lx;
char *dtext; /* dequoted TEXT, if needed */
+ size_t si1, si2;
size_t len1, len2;
#if defined (HANDLE_MULTIBYTE)
int v;
len1 = strlen (match_list[i]);
len2 = strlen (match_list[i + 1]);
- for (si = 0; (c1 = match_list[i][si]) && (c2 = match_list[i + 1][si]); si++)
+ for (si1 = si2 = 0; (c1 = match_list[i][si1]) && (c2 = match_list[i + 1][si2]); si1++,si2++)
{
if (_rl_completion_case_fold)
{
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
- v1 = MBRTOWC (&wc1, match_list[i]+si, len1 - si, &ps1);
- v2 = MBRTOWC (&wc2, match_list[i+1]+si, len2 - si, &ps2);
+ v1 = MBRTOWC (&wc1, match_list[i]+si1, len1 - si1, &ps1);
+ v2 = MBRTOWC (&wc2, match_list[i+1]+si2, len2 - si2, &ps2);
if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2))
{
if (c1 != c2) /* do byte comparison */
}
if (wc1 != wc2)
break;
- else if (v1 > 1)
- si += v1 - 1;
+
+ if (v1 > 1)
+ si1 += v1 - 1;
+ if (v2 > 1)
+ si2 += v2 - 1;
}
else
#endif
break;
}
+ si = MIN (si1, si2); /* use shorter of matches of different length */
if (low > si)
low = si;
}
cxt = _rl_rscxt_alloc (flags);
- rl_maybe_replace_line ();
_rl_saved_line_for_readstr = _rl_alloc_saved_line ();
-
rl_undo_list = 0;
rl_line_buffer[0] = 0;
# define ZBUFSIZ 4096
#endif
-extern int executing_builtin;
+extern int executing_builtin, interrupt_state;
extern void check_signals_and_traps (void);
extern void check_signals (void);
extern int signal_is_trapped (int);
extern int read_builtin_timeout (int);
+/* Forward declarations */
+void zreset (void);
+
/* Read LEN bytes from FD into BUF. Retry the read on EINTR. Any other
error causes the loop to break. */
ssize_t
/* XXX - bash-5.0 */
/* We check executing_builtin and run traps here for backwards compatibility */
if (executing_builtin)
- check_signals_and_traps (); /* XXX - should it be check_signals()? */
+ {
+ if (interrupt_state)
+ zreset ();
+ check_signals_and_traps (); /* XXX - should it be check_signals()? */
+ }
else
check_signals ();
errno = t;
} \
} while (0)
+#define ZRESET() \
+ do { \
+ if (interrupt_state) zreset (); \
+ } while (0)
+
#endif /* _QUIT_H_ */
w = redir->redirector.filename;
v = bind_var_to_int (w->word, fd, 0);
- if (v == 0 || readonly_p (v) || noassign_p (v))
+ if (v == 0 || ASSIGN_DISALLOWED (v, 0))
return BADVAR_REDIRECT;
stupidly_hack_special_variables (w->word);
CQ_RETURN(si);
if (string[i+1] == LPAREN)
- temp = extract_delimited_string (string, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND|completeflag); /* ) */
+ temp = extract_command_subst (string, &si, SX_NOALLOC|SX_COMMAND|completeflag);
else
temp = extract_dollar_brace_string (string, &si, 0, SX_NOALLOC|completeflag);
CHECK_STRING_OVERRUN (i, si, slen, c);
{
v = find_variable (name); /* follows namerefs */
newname = (v == 0) ? nameref_transform_name (name, flags) : v->name;
- if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
+ if (v && ASSIGN_DISALLOWED (v, flags))
{
if (readonly_p (v))
err_readonly (name);
v = 0;
if (v == 0)
v = find_global_variable (name);
- if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
+ if (v && ASSIGN_DISALLOWED (v, flags))
{
if (readonly_p (v))
err_readonly (name);
else
{
v = assign_array_from_string (name, value, flags);
- if (v && ((readonly_p (v) && (flags & ASS_FORCE) == 0) || noassign_p (v)))
+ if (v && ASSIGN_DISALLOWED (v, flags))
{
if (readonly_p (v))
err_readonly (name);
#endif /* ARRAY_VARS */
v = bind_variable (vname, t1, 0);
- if (v == 0 || readonly_p (v) || noassign_p (v)) /* expansion error */
+ if (v == 0 || ASSIGN_DISALLOWED (v, 0)) /* expansion error */
{
if ((v == 0 || readonly_p (v)) && interactive_shell == 0 && posixly_correct)
{
echo X
break
echo Y
+
+# arithmetic for commands need to skip over command substitutions
+for (( $(case x in x) esac);; )); do break; done
+for (( ${ case x in x) esac; };; )); do break; done
}
else if (entry->assign_func) /* array vars have assign functions now */
{
- if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry))
+ if (ASSIGN_DISALLOWED (entry, aflags))
{
if (readonly_p (entry))
err_readonly (name_cell (entry));
else
{
assign_value:
- if ((readonly_p (entry) && (aflags & ASS_FORCE) == 0) || noassign_p (entry))
+ if (ASSIGN_DISALLOWED (entry, aflags))
{
if (readonly_p (entry))
err_readonly (name_cell (entry));
}
else
newname = name_cell (var); /* no-op if not nameref */
-
- if (var && (readonly_p (var) || noassign_p (var)))
+
+ if (var && ASSIGN_DISALLOWED (var, 0))
{
if (readonly_p (var))
err_readonly (name);
/* Special value for nameref with invalid value for creation or assignment */
extern SHELL_VAR nameref_invalid_value;
#define INVALID_NAMEREF_VALUE (void *)&nameref_invalid_value
+
+/* Assignment statements */
+#define ASSIGN_DISALLOWED(v, f) \
+ ((readonly_p (v) && (f&ASS_FORCE) == 0) || noassign_p (v))
/* Stuff for hacking variables. */
typedef int sh_var_map_func_t (SHELL_VAR *);