9/23
----
-execute_command.c
+execute_cmd.c
- execute_in_subshell: call without_job_control for both job control
and non-job-control builds to avoid waiting for last_made_pid
inherited from parent shell. Related to fix from 8/4 to
<michael.osipov@siemens.com>
configure.ac
- - hpux: add -DTGETENT_BROKEN to LOCAL_CFLAGS. Still need to do this
- in the readline configure.ac
+ - hpux: add -DTGETENT_BROKEN to LOCAL_CFLAGS
execute_cmd.c
- select_builtin: set executing_builtin around the call to read_builtin
- The Restricted Shell: add some language detailing the weaknesses of
the restricted shell mode in isolation, inspired by a discussion on
the zsh mailing list
+
+ 5/15
+ ----
+xmalloc.h
+ - malloc: define to sh_malloc to get file and line information from
+ malloc (not xmalloc) calls. From a suggestion by achurch@achurch.org
+ (Andrew Church)
+
+builtins/evalstring.c
+ - parse_and_execute: make sure the parser is not expanding an alias
+ before terminating the loop that processes characters in the string.
+ Fixes problem with -c commands that end with an alias reported by
+ Yu Kou <ckyoog@gmail.com>
+ - should_suppress_fork: make sure that we don't try to optimize out a
+ fork if the parser is still expanding an alias
+
+ 5/16
+ ----
+lib/readline/misc.c
+ - rl_get_previous_history: if previous_history() returns NULL, only
+ free the saved history if we were the ones who saved it; leave any
+ existing saved history entry alone. Fixes problem with ^N not working
+ at the end of the history if we previously moved back to the start
+ of history
+
+lib/readline/histfile.c
+ - read_history_range: when reading until FROM lines with a history
+ file that has timestamps, make sure to skip to the end of the command
+ line corresponding to the FROMth line instead of leaving line_start
+ pointing to it, and keep track of the start of the last timestamp in
+ last_ts for use by the loop below. Fix for history -n bug reported
+ by HIROSE Masaaki <hirose31@gmail.com>
+
+lib/readline/display.c
+ - init_line_structures: if, for some reason, _rl_screenwidth ends up
+ bigger than the line_size default of 1024 (e.g., gdb's setting the
+ terminal width to 0), make sure line_size is at least _rl_screenwidth.
+ From a report by Tom de Vries <tdevries@suse.de>
+
+ 5/17
+ ----
+variables.c
+ - brand: split the code into a function that generates a 32-bit value
+ given the last value in the sequence (intrand32) and a function that
+ returns a 16-bit random number (brand)
+ - seedrand: small change in hopes of adding slightly more entropy
+ - brand: modify the 16-bit version to XOR the top 16 bits of the 32-bit
+ seed with the bottom 16 bits and return the lower 15 bits of that
+ result as before. Based on an analysis by Andrew Church
+ <achurch+bash@achurch.org>
+
+ 5/18
+ ----
+variables.c
+ - genseed: break code that generates the 32-bit seed for the RNG into
+ a separate function; call from seedrand
+ - {brand32,sbrand32,seedrand32}: new 32-bit versions of the random
+ number generator functions that use the entire 32-bit internal value.
+ Prep for systems that don't have /dev/urandom or arc4random()
+ - perturb_rand32: shake up the 32-bit LCRNG in subshells
+
+ 5/19
+ ----
+variables.c
+ - get_urandom32: get a 32-bit random number by using the first one of
+ these that succeeds: reading from /dev/urandom (if available),
+ calling arc4random (if available), and using the internal 32-bit
+ RNG (always available)
+ - URANDOM: expand to a 32-bit random number. This is not a LCRNG, so
+ the numbers shouldn't have any relationship to previous returned
+ values. Assignments are accepted but have no effect on the sequence.
+ Not documented yet
tests/alias2.sub f
tests/alias3.sub f
tests/alias4.sub f
+tests/alias5.sub f
tests/alias.right f
tests/appendop.tests f
tests/appendop1.sub f
return (startup_state == 2 && parse_and_execute_level == 1 &&
running_trap == 0 &&
*bash_input.location.string == '\0' &&
+ parser_expanding_alias () == 0 &&
command->type == cm_simple &&
signal_is_trapped (EXIT_TRAP) == 0 &&
signal_is_trapped (ERROR_TRAP) == 0 &&
COMMAND *command;
{
return (*bash_input.location.string == '\0' &&
+ parser_expanding_alias () == 0 &&
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
command->value.Connection->second->type == cm_simple);
}
with_input_from_string (string, from_file);
clear_shell_input_line ();
- while (*(bash_input.location.string))
+ while (*(bash_input.location.string) || parser_expanding_alias ())
{
command = (COMMAND *)NULL;
ostring = string;
with_input_from_string (string, from_file);
- while (*(bash_input.location.string))
+ while (*(bash_input.location.string)) /* XXX - parser_expanding_alias () ? */
{
command = (COMMAND *)NULL;
/* Presence of system and C library functions. */
+/* Define if you have the arc4random function. */
+#undef HAVE_ARC4RANDOM
+
/* Define if you have the asprintf function. */
#undef HAVE_ASPRINTF
#! /bin/sh
-# From configure.ac for Bash 5.0, version 5.009.
+# From configure.ac for Bash 5.0, version 5.010.
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for bash 5.0-maint.
#
fi
done
+for ac_func in arc4random
+do :
+ ac_fn_c_check_func "$LINENO" "arc4random" "ac_cv_func_arc4random"
+if test "x$ac_cv_func_arc4random" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_ARC4RANDOM 1
+_ACEOF
+
+fi
+done
+
+
ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd"
if test "x$ac_cv_func_getcwd" = xyes; then :
$as_echo "#define HAVE_GETCWD 1" >>confdefs.h
# 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.0, version 5.009])dnl
+AC_REVISION([for Bash 5.0, version 5.010])dnl
define(bashvers, 5.0)
define(relstatus, maint)
AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit)
AC_CHECK_FUNCS(getpwent getpwnam getpwuid)
AC_CHECK_FUNCS(mkstemp mkdtemp)
+AC_CHECK_FUNCS(arc4random)
+
AC_REPLACE_FUNCS(getcwd memset)
AC_REPLACE_FUNCS(strcasecmp strcasestr strerror strftime strnlen strpbrk strstr)
AC_REPLACE_FUNCS(strtod strtol strtoul strtoll strtoull strtoimax strtoumax)
{
register int n;
+ if (line_size <= _rl_screenwidth) /* XXX - for gdb */
+ line_size = _rl_screenwidth + 1;
+
if (invisible_line == 0) /* initialize it */
{
if (line_size < minsize)
}
has_timestamps = HIST_TIMESTAMP_START (buffer);
- history_multiline_entries += has_timestamps && history_write_timestamps;
+ history_multiline_entries += has_timestamps && history_write_timestamps;
/* Skip lines until we are at FROM. */
+ if (has_timestamps)
+ last_ts = buffer;
for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
if (*line_end == '\n')
{
line. We should check more extensively here... */
if (HIST_TIMESTAMP_START(p) == 0)
current_line++;
+ else
+ last_ts = p;
line_start = p;
+ /* If we are at the last line (current_line == from) but we have
+ timestamps (has_timestamps), then line_start points to the
+ text of the last command, and we need to skip to its end. */
+ if (current_line >= from && has_timestamps)
+ {
+ for (line_end = p; line_end < bufend && *line_end != '\n'; line_end++)
+ ;
+ line_start = (*line_end == '\n') ? line_end + 1 : line_end;
+ }
}
/* If there are lines left to gobble, then gobble them now. */
rl_get_previous_history (int count, int key)
{
HIST_ENTRY *old_temp, *temp;
+ int had_saved_line;
if (count < 0)
return (rl_get_next_history (-count, key));
_rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
/* If we don't have a line saved, then save this one. */
+ had_saved_line = _rl_saved_line_for_history != 0;
rl_maybe_save_line ();
/* If the current line has changed, save the changes. */
if (temp == 0)
{
- _rl_free_saved_history_line ();
+ if (had_saved_line == 0)
+ _rl_free_saved_history_line ();
rl_ding ();
}
else
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
+BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
bad
0
<|cat>
+foo
+bar
+baz
+foo
+bar
+baz
${THIS_SH} ./alias2.sub
${THIS_SH} ./alias3.sub
${THIS_SH} ./alias4.sub
+${THIS_SH} ./alias5.sub
--- /dev/null
+# -c commands ending with multi-line aliases; post-bash-5.0
+
+: ${THIS_SH:=./bash}
+
+${THIS_SH} -c "shopt -s expand_aliases &>/dev/null;
+alias myalias='/bin/echo foo
+echo bar
+echo baz'
+myalias"
+
+${THIS_SH} -c "shopt -s expand_aliases &>/dev/null;
+alias myalias='echo foo
+echo bar
+echo baz'
+myalias"
+# this depends on the sequence of random numbers from the internal LCRNG
RANDOM=42
(( dice[RANDOM%6+1 + RANDOM%6+1]++ ))
-echo ${dice[5]}
+echo ${dice[6]}
(( ++dice[RANDOM%6+1 + RANDOM%6+1] ))
-echo ${dice[6]}
+echo ${dice[7]}
v=4
DIND=20
(( dice[DIND%6 + 1]=v ))
echo ${dice[3]}
+(( dice[DIND/v]+=2 ))
RANDOM=42
(( dice[RANDOM%6+1 + RANDOM%6+1]+=v ))
-echo ${dice[5]}
+echo ${dice[6]}
(( dice[RANDOM%6+1 + RANDOM%6+1]-=v ))
-echo ${dice[6]}
+echo ${dice[7]}
(( dice[RANDOM%6+1 + RANDOM%6+1]+=2 ))
-echo ${dice[11]}
+echo ${dice[8]}
(( dice[RANDOM%6+1 + RANDOM%6+1]*=2 ))
-echo ${dice[11]}
+echo ${dice[5]}
unset dice1 dice2
RANDOM=42
#endif
#include "bashansi.h"
#include "bashintl.h"
+#include "filecntl.h"
#define NEED_XTRACE_SET_DECL
static SHELL_VAR *get_seconds __P((SHELL_VAR *));
static SHELL_VAR *init_seconds_var __P((void));
+static u_bits32_t intrand32 __P((u_bits32_t));
+static u_bits32_t genseed __P((void));
+
static int brand __P((void));
static void sbrand __P((unsigned long)); /* set bash random number generator. */
static void seedrand __P((void)); /* seed generator randomly */
+
+static u_bits32_t brand32 __P((void));
+static void sbrand32 __P((u_bits32_t));
+static void seedrand32 __P((void));
+static void perturb_rand32 __P((void));
+static u_bits32_t get_urandom32 __P((void));
+
static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));
static SHELL_VAR *get_random __P((SHELL_VAR *));
+static SHELL_VAR *get_urandom __P((SHELL_VAR *));
+
static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));
static SHELL_VAR *get_lineno __P((SHELL_VAR *));
}
#endif /* HISTORY */
- /* Seed the random number generator. */
+ /* Seed the random number generators. */
seedrand ();
+ seedrand32 ();
/* Handle some "special" variables that we may have inherited from a
parent shell. */
static int last_random_value;
static int seeded_subshell = 0;
-#define BASH_RANDOM_16 1
-
-#if BASH_RANDOM_16
-# define BASH_RAND_MAX 32767 /* 0x7fff - 16 bits */
-#else
-# define BASH_RAND_MAX 0x7fffffff /* 32 bits */
-#endif
-
-/* Returns a pseudo-random number between 0 and 32767. */
-static int
-brand ()
+/* Returns a 32-bit pseudo-random number. */
+static u_bits32_t
+intrand32 (last)
+ u_bits32_t last;
{
/* Minimal Standard generator from
"Random number generators: good ones are hard to find",
We split up the calculations to avoid overflow.
- h = rseed / q; l = x - h * q; t = a * l - h * r
+ h = last / q; l = x - h * q; t = a * l - h * r
m = 2147483647, a = 16807, q = 127773, r = 2836
There are lots of other combinations of constants to use; look at
https://www.gnu.org/software/gsl/manual/html_node/Other-random-number-generators.html#Other-random-number-generators */
bits32_t h, l, t;
+ u_bits32_t ret;
/* Can't seed with 0. */
- if (rseed == 0)
- rseed = 123459876;
- h = rseed / 127773;
- l = rseed - (127773 * h);
+ ret = (last == 0) ? 123459876 : last;
+ h = ret / 127773;
+ l = ret - (127773 * h);
t = 16807 * l - 2836 * h;
- rseed = (t < 0) ? t + 0x7fffffff : t;
+ ret = (t < 0) ? t + 0x7fffffff : t;
+
+ return (ret);
+}
+
+static u_bits32_t
+genseed ()
+{
+ struct timeval tv;
+ u_bits32_t iv;
- return ((unsigned int)(rseed & BASH_RAND_MAX)); /* was % BASH_RAND_MAX+1 */
+ gettimeofday (&tv, NULL);
+ iv = (u_bits32_t)seedrand; /* let the compiler truncate */
+ iv = tv.tv_sec ^ tv.tv_usec ^ getpid () ^ getppid () ^ current_user.uid ^ iv;
+ return (iv);
+}
+
+#define BASH_RAND_MAX 32767 /* 0x7fff - 16 bits */
+
+/* Returns a pseudo-random number between 0 and 32767. */
+static int
+brand ()
+{
+ unsigned int ret;
+
+ rseed = intrand32 (rseed);
+ ret = (rseed >> 16) ^ (rseed & 65535);
+ return (ret & BASH_RAND_MAX);
}
/* Set the random number generator seed to SEED. */
static void
seedrand ()
{
- struct timeval tv;
- SHELL_VAR *v;
+ u_bits32_t iv;
- gettimeofday (&tv, NULL);
-#if 0
- v = find_variable ("BASH_VERSION");
- sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid () ^ ((u_bits32_t)&v & 0x7fffffff));
+ iv = genseed ();
+ sbrand (iv);
+}
+
+static u_bits32_t rseed32 = 1073741823;
+static int last_rand32;
+
+static int urandfd = -1;
+
+#define BASH_RAND32_MAX 0x7fffffff /* 32 bits */
+
+/* Returns a 32-bit pseudo-random number between 0 and 4294967295. */
+static u_bits32_t
+brand32 ()
+{
+ u_bits32_t ret;
+
+ rseed32 = intrand32 (rseed32);
+ return (rseed32 & BASH_RAND32_MAX);
+}
+
+static void
+sbrand32 (seed)
+ u_bits32_t seed;
+{
+ rseed32 = seed;
+ last_rand32 = seed;
+}
+
+static void
+seedrand32 ()
+{
+ u_bits32_t iv;
+
+ iv = genseed ();
+ sbrand32 (iv);
+}
+
+static void
+perturb_rand32 ()
+{
+ rseed32 ^= genseed ();
+}
+
+/* Force another attempt to open /dev/urandom on the next call to get_urandom32 */
+void
+urandom_close ()
+{
+ if (urandfd >= 0)
+ close (urandfd);
+ urandfd = -1;
+}
+
+static u_bits32_t
+get_urandom32 ()
+{
+ u_bits32_t ret;
+ int n;
+ static int urand_unavail = 0;
+
+ if (urandfd == -1 && urand_unavail == 0)
+ {
+ urandfd = open ("/dev/urandom", O_RDONLY, 0);
+ if (urandfd >= 0)
+ SET_CLOSE_ON_EXEC (urandfd);
+ else
+ urand_unavail = 1;
+ }
+ if (urandfd >= 0 && (n = read (urandfd, (char *)&ret, sizeof (ret))) == sizeof (ret))
+ return (last_rand32 = ret);
+#if defined (HAVE_ARC4RANDOM)
+ ret = arc4random ();
#else
- sbrand (tv.tv_sec ^ tv.tv_usec ^ getpid () ^ getppid () ^ current_user.uid ^ current_user.gid);
+ if (subshell_environment)
+ perturb_rand32 ();
+ do
+ ret = brand32 ();
+ while (ret == last_rand32);
#endif
+ return (last_rand32 = ret);
}
static SHELL_VAR *
do
rv = brand ();
while (rv == last_random_value);
- return rv;
+
+ return (last_random_value = rv);
}
static SHELL_VAR *
char *p;
rv = get_random_number ();
- last_random_value = rv;
+ p = itos (rv);
+
+ FREE (value_cell (var));
+
+ VSETATTR (var, att_integer);
+ var_setvalue (var, p);
+ return (var);
+}
+
+static SHELL_VAR *
+get_urandom (var)
+ SHELL_VAR *var;
+{
+ u_bits32_t rv;
+ char *p;
+
+ rv = get_urandom32 ();
p = itos (rv);
FREE (value_cell (var));
INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
VSETATTR (v, att_integer);
+ INIT_DYNAMIC_VAR ("URANDOM", (char *)NULL, get_urandom, (sh_var_assign_func_t *)NULL);
+ VSETATTR (v, att_integer);
INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
VSETATTR (v, att_integer|att_regenerate);
#undef free
#endif
#define free(x) sh_xfree((x), __FILE__, __LINE__)
+
+extern PTR_T sh_malloc __P((size_t, const char *, int));
+
+#ifdef malloc
+#undef malloc
+#endif
+#define malloc(x) sh_malloc((x), __FILE__, __LINE__)
+
#endif /* USING_BASH_MALLOC */
#endif /* _XMALLOC_H_ */