commit bash-20150501 snapshot

This commit is contained in:
Chet Ramey
2015-05-15 11:05:19 -04:00
parent 48abf0fdc9
commit 34ec187607
56 changed files with 731 additions and 108 deletions
+105
View File
@@ -8413,3 +8413,108 @@ lib/readline/{rltty,terminal}.c
- sys/ioctl.h: include unconditionally for ioctl declaration, avoid issues
with `implicit declaration' warnings. Issue originally raised on gdb
list by Chen Gang <xili_gchen_5257@hotmail.com>
4/27
----
lib/malloc/table.c
- mem_table: now a circular buffer showing the state of the last
REG_TABLE_SIZE allocations rather than a hash table that quickly fills
up
builtins/declare.def
- typeset_builtin: add -n to list of supported options. Omission reported
by Valentin Bajrami <valentin.bajrami@gmail.com>
unwind_prot.c
- use object caches instead of malloc/free to allocate and deallocate
unwind-protect elements
- uwp_init: initialize unwind-protect element object cache
unwind_prot.h
- uwp_init: extern declaration
shell.c
- main: call uwp_init right after calling cmd_init -- initialize all the
object caches at the same place
lib/malloc/table.[ch]
- mlocation_table: new table to keep track of allocation locations by
file and line, functions to initialize table, record an allocation,
and dump the table to stderr
- mregister_alloc: call mlocation_register_alloc to record the location
(source file/line) for each allocation to pinpoint malloc hot spots
by number of calls. More detail than gprof
parse.y
- set_line_mbstate: replace free/xmalloc pair with xrealloc call
- read_token_word: call alloc_word_desc instead of xmalloc so we can take
advantage of the WORD_DESC cache
4/28
----
execute_cmd.c
- execute_simple_command: if command execution fails because the command
is a directory, and the `autocd' option is set, add a `--' argument
to the constructed `cd' command to protect against command names with
the same name as options to `cd'. Report and fix from
isabella parakiss <izaberina@gmail.com>
4/30
----
jobs.c
- printable_job_status, j_strsignal: change calls to strcpy and sprintf
that write to retcode_name_buffer to use strncpy and snprintf to
avoid buffer overflows caused by malicious translations. Bug and fix
from Trammell Hudson <Trammell.Hudson@twosigma.com>
5/1
---
strtrans.c
- ansicstr: make sure the buffer is at least 12 bytes to ensure enough
space for any eventual call to u32cesc for one multibyte char
5/4
---
jobs.c
- wait_for: if an interactive shell is running a loop and waiting for
a non-builtin command to exit, and the command exits due to SIGINT,
act as if the shell received the SIGINT as well and break the loop.
This matches the behavior when the shell is running a builtin command
in a loop, and when running a non-builtin command outside a loop, and
seems more broadly useful than running the trap handler over and over
again. Report originally from Kaz Kylheku <kkylheku@gnu.org>
builtins/set.def
- unset_builtin: use different variables for keeping the state of the
-f and -v options than the loop uses to decide whether or not to
treat a name as a function or a variable. Fixes problem with
unset_function setting `sticking' after you unset a function when
invoked with no options. Bug report from Dreamcat4
<dreamcat4@gmail.com>
shell.c
- open_shell_script: set running_shell_script to 1, set to 0 in every
other case (new variable)
- main: when checking whether or not to call start_debugger, test
running_shell_script instead of dollar_vars[1]. The goal is to not
invoke the debugger for interactive shells but allow it to run for
things like `bash --debugger -i /tmp/script'. Problem reported by
Rocky Bernstein <rocky@gnu.org>
lib/readline/histexpand.c
- history_event_delimiter_chars: new (as yet undocumented) variable
containing by default characters that can delimit a history event
specifier without requiring a `:': "^$*%-" as the documentation has
always said. Fixes bug reported by Anders Granlund
<anders.granlund.0@gmail.com>
5/10
----
lib/glob/gmisc.c
- match_pattern_char, match_pattern_wchar: if passed an empty string,
return a match if the first character of the pattern is `*'
subst.c
- pat_subst: change to allow empty strings to be replaced as long as
pattern matches empty string. Report and fix from isabella parakiss
<izaberina@gmail.com>
+6
View File
@@ -857,6 +857,7 @@ tests/builtins2.sub f
tests/builtins3.sub f
tests/builtins4.sub f
tests/builtins5.sub f
tests/builtins6.sub f
tests/source1.sub f
tests/source2.sub f
tests/source3.sub f
@@ -872,6 +873,7 @@ tests/casemod.right f
tests/comsub.tests f
tests/comsub.right f
tests/comsub1.sub f
tests/comsub2.sub f
tests/comsub-eof.tests f
tests/comsub-eof0.sub f
tests/comsub-eof1.sub f
@@ -929,6 +931,8 @@ tests/errors.right f
tests/errors1.sub f
tests/errors2.sub f
tests/errors3.sub f
tests/errors4.sub f
tests/errors5.sub f
tests/execscript f
tests/exec.right f
tests/exec1.sub f 755
@@ -1043,6 +1047,7 @@ tests/nameref5.sub f
tests/nameref6.sub f
tests/nameref7.sub f
tests/nameref8.sub f
tests/nameref9.sub f
tests/nameref.right f
tests/new-exp.tests f
tests/new-exp1.sub f
@@ -1261,6 +1266,7 @@ tests/vredir3.sub f
tests/vredir4.sub f
tests/vredir5.sub f
tests/vredir6.sub f
tests/vredir7.sub f
tests/misc/dev-tcp.tests f
tests/misc/perf-script f
tests/misc/perftest f
+1 -1
View File
@@ -171,7 +171,7 @@ find_compopt (name)
/* Build the actions and compspec options from the options specified in LIST.
ACTP is a pointer to an unsigned long in which to place the bitmap of
actions. OPTP is a pointer to an unsigned long in which to place the
btmap of compspec options (arguments to `-o'). PP, if non-null, gets 1
bitmap of compspec options (arguments to `-o'). PP, if non-null, gets 1
if -p is supplied; RP, if non-null, gets 1 if -r is supplied.
If either is null, the corresponding option generates an error.
This also sets variables corresponding to options that take arguments as
+1 -1
View File
@@ -62,7 +62,7 @@ $END
$BUILTIN typeset
$FUNCTION declare_builtin
$SHORT_DOC typeset [-aAfFgilrtux] [-p] name[=value] ...
$SHORT_DOC typeset [-aAfFgilnrtux] [-p] name[=value] ...
Set variable values and attributes.
Obsolete. See `help declare'.
+8 -3
View File
@@ -796,9 +796,11 @@ unset_builtin (list)
WORD_LIST *list;
{
int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
int global_unset_func, global_unset_var;
char *name;
unset_function = unset_variable = unset_array = nameref = any_failed = 0;
global_unset_func = global_unset_var = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "fnv")) != -1)
@@ -806,10 +808,10 @@ unset_builtin (list)
switch (opt)
{
case 'f':
unset_function = 1;
global_unset_func = 1;
break;
case 'v':
unset_variable = 1;
global_unset_var = 1;
break;
case 'n':
nameref = 1;
@@ -822,7 +824,7 @@ unset_builtin (list)
list = loptend;
if (unset_function && unset_variable)
if (global_unset_func && global_unset_var)
{
builtin_error (_("cannot simultaneously unset a function and a variable"));
return (EXECUTION_FAILURE);
@@ -840,6 +842,9 @@ unset_builtin (list)
name = list->word->word;
unset_function = global_unset_func;
unset_variable = global_unset_var;
#if defined (ARRAY_VARS)
unset_array = 0;
if (!unset_function && valid_array_reference (name, 0))
+1 -1
View File
@@ -86,7 +86,7 @@ static int display_traps __P((WORD_LIST *));
trap -p [sigspec ...]
trap [--]
Set things up so that ARG is executed when SIGNAL(s) N is recieved.
Set things up so that ARG is executed when SIGNAL(s) N is received.
If ARG is the empty string, then ignore the SIGNAL(s). If there is
no ARG, then set the trap for SIGNAL(s) to its original value. Just
plain "trap" means to print out the list of commands associated with
+6 -5
View File
@@ -643,7 +643,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
if (s)
subshell_exit (last_command_exit_value);
else
exit (last_command_exit_value);
sh_exit (last_command_exit_value);
/* NOTREACHED */
}
else
@@ -3926,7 +3926,7 @@ is_dirname (pathname)
int ret;
temp = search_for_command (pathname, 0);
ret = (temp ? file_isdir (temp) : file_isdir (pathname));
ret = temp ? file_isdir (temp) : file_isdir (pathname);
free (temp);
return ret;
}
@@ -4086,7 +4086,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
pipe_in, pipe_out,
already_forked ? 0 : async);
if (already_forked)
exit (result);
sh_exit (result);
else
{
bind_lastarg ((char *)NULL);
@@ -4283,6 +4283,7 @@ run_builtin:
if (autocd && interactive && words->word && is_dirname (words->word->word))
{
words = make_word_list (make_word ("--"), words);
words = make_word_list (make_word ("cd"), words);
xtrace_print_word_list (words, 0);
goto run_builtin;
@@ -4850,14 +4851,14 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var,
fflush (stdout);
if (r == EX_USAGE)
r = EX_BADUSAGE;
exit (r);
sh_exit (r);
}
}
else
{
r = execute_function (var, words, flags, fds_to_close, async, 1);
fflush (stdout);
exit (r);
sh_exit (r);
}
}
+1 -3
View File
@@ -407,9 +407,7 @@ fd_ispipe (fd)
int fd;
{
errno = 0;
if (lseek ((fd), 0L, SEEK_CUR) < 0)
return (errno == ESPIPE);
return 0;
return ((lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE));
}
/* There is a bug in the NeXT 2.1 rlogind that causes opens
+1 -1
View File
@@ -124,7 +124,7 @@ typedef struct {
int token;
} STRING_INT_ALIST;
/* A macro to avoid making an unneccessary function call. */
/* A macro to avoid making an unnecessary function call. */
#define REVERSE_LIST(list, type) \
((list && list->next) ? (type)list_reverse ((GENERIC_LIST *)list) \
: (type)(list))
+16 -5
View File
@@ -1489,7 +1489,7 @@ j_strsignal (s)
if (x == 0)
{
x = retcode_name_buffer;
sprintf (x, _("Signal %d"), s);
snprintf (x, sizeof(retcode_name_buffer), _("Signal %d"), s);
}
return x;
}
@@ -1512,7 +1512,7 @@ printable_job_status (j, p, format)
else
{
temp = retcode_name_buffer;
sprintf (temp, _("Stopped(%s)"), signal_name (WSTOPSIG (p->status)));
snprintf (temp, sizeof(retcode_name_buffer), _("Stopped(%s)"), signal_name (WSTOPSIG (p->status)));
}
}
else if (RUNNING (j))
@@ -1528,11 +1528,14 @@ printable_job_status (j, p, format)
temp = retcode_name_buffer;
es = WEXITSTATUS (p->status);
if (es == 0)
strcpy (temp, _("Done"));
{
strncpy (temp, _("Done"), sizeof (retcode_name_buffer) - 1);
temp[sizeof (retcode_name_buffer) - 1] = '\0';
}
else if (posixly_correct)
sprintf (temp, _("Done(%d)"), es);
snprintf (temp, sizeof(retcode_name_buffer), _("Done(%d)"), es);
else
sprintf (temp, _("Exit %d"), es);
snprintf (temp, sizeof(retcode_name_buffer), _("Exit %d"), es);
}
else
temp = _("Unknown status");
@@ -2709,6 +2712,14 @@ if (job == NO_JOB)
SIGINT signal handler; maybe it should. */
if (signal_is_trapped (SIGINT) == 0 && (loop_level || (shell_compatibility_level > 32 && executing_list)))
ADDINTERRUPT;
/* Call any SIGINT trap handler if the shell is running a loop, so
the loop can be broken. This seems more useful and matches the
behavior when the shell is running a builtin command in a loop
when it is interrupted. Change ADDINTERRUPT to
trap_handler (SIGINT) to run the trap without interrupting the
loop. */
else if (signal_is_trapped (SIGINT) && loop_level)
ADDINTERRUPT;
else
{
putchar ('\n');
+2 -2
View File
@@ -64,7 +64,7 @@ match_pattern_wchar (wpat, wstring, flags)
wchar_t wc;
if (*wstring == 0)
return (0);
return (*wpat == L'*'); /* XXX - allow only * to match empty string */
switch (wc = *wpat++)
{
@@ -249,7 +249,7 @@ match_pattern_char (pat, string, flags)
char c;
if (*string == 0)
return (0);
return (*pat == '*'); /* XXX - allow only * to match empty string */
switch (c = *pat++)
{
+141 -43
View File
@@ -37,14 +37,25 @@ extern int malloc_register;
#ifdef MALLOC_REGISTER
#define FIND_ALLOC 0x01 /* allocate new entry or find existing */
#define FIND_EXIST 0x02 /* find existing entry */
extern FILE *_imalloc_fopen __P((char *, char *, char *, char *, size_t));
#define FIND_ALLOC 0x01 /* find slot for new allocation */
#define FIND_EXIST 0x02 /* find slot for existing entry for free() or search */
static int table_count = 0;
static int table_allocated = 0;
static int table_bucket_index = REG_TABLE_SIZE-1;
static mr_table_t mem_table[REG_TABLE_SIZE];
static mr_table_t mem_overflow;
#ifndef STREQ
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
#endif
static int location_table_index = 0;
static int location_table_count = 0;
static ma_table_t mlocation_table[REG_TABLE_SIZE];
/*
* NOTE: taken from dmalloc (http://dmalloc.com) and modified.
*/
@@ -72,8 +83,15 @@ which_bucket (mem)
{
return (mt_hash ((unsigned char *)mem) & (REG_TABLE_SIZE-1));
}
#else
#define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) & (REG_TABLE_SIZE-1));
#define next_bucket() ((table_bucket_index + 1) & (REG_TABLE_SIZE-1))
#define next_entry(mem) ((mem == mem_table + REG_TABLE_SIZE - 1) ? mem_table : ++mem)
#define prev_bucket() (table_bucket_index == 0 ? REG_TABLE_SIZE-1 : table_bucket_index-1)
#define prev_entry(mem) ((mem == mem_table) ? mem_table + REG_TABLE_SIZE - 1 : mem - 1)
#endif
static mr_table_t *
@@ -83,60 +101,37 @@ find_entry (mem, flags)
{
unsigned int bucket;
register mr_table_t *tp;
mr_table_t *endp, *lastp;
mr_table_t *endp;
if (mem_overflow.mem == mem)
return (&mem_overflow);
bucket = which_bucket (mem); /* get initial hash */
tp = endp = mem_table + bucket;
lastp = mem_table + REG_TABLE_SIZE;
/* If we want to insert an allocation entry just use the next slot */
if (flags & FIND_ALLOC)
{
table_bucket_index = next_bucket();
table_count++;
tp = mem_table + table_bucket_index;
memset(tp, 0, sizeof (mr_table_t)); /* overwrite next existing entry */
return tp;
}
tp = endp = mem_table + table_bucket_index;
/* search for last allocation corresponding to MEM, return entry pointer */
while (1)
{
if (tp->mem == mem)
return (tp);
if (tp->mem == 0 && (flags & FIND_ALLOC))
{
table_count++;
return (tp);
}
tp++;
tp = prev_entry (tp);
if (tp == lastp) /* wrap around */
tp = mem_table;
if (tp == endp && (flags & FIND_EXIST))
/* if we went all the way around and didn't find it, return NULL */
if (tp == endp)
return ((mr_table_t *)NULL);
if (tp == endp && (flags & FIND_ALLOC))
break;
}
/* oops. table is full. replace an existing free entry. */
do
{
/* If there are no free entries, punt right away without searching. */
if (table_allocated == REG_TABLE_SIZE)
break;
if (tp->flags & MT_FREE)
{
memset(tp, 0, sizeof (mr_table_t));
return (tp);
}
tp++;
if (tp == lastp)
tp = mem_table;
}
while (tp != endp);
/* wow. entirely full. return mem_overflow dummy entry. */
tp = &mem_overflow;
memset (tp, 0, sizeof (mr_table_t));
return tp;
return (mr_table_t *)NULL;
}
mr_table_t *
@@ -186,6 +181,8 @@ mregister_alloc (tag, mem, size, file, line)
blocked_sigs = 1;
}
mlocation_register_alloc (file, line);
tentry = find_entry (mem, FIND_ALLOC);
if (tentry == 0)
@@ -293,7 +290,9 @@ _register_dump_table(fp)
{
entry = mem_table[i];
if (entry.mem)
fprintf (fp, "[%d] %p:%d:%s:%s:%s:%d:%d:%d\n", i,
fprintf (fp, "%s[%d] %p:%d:%s:%s:%s:%d:%d:%d\n",
(i == table_bucket_index) ? "*" : "",
i,
entry.mem, entry.size,
_entry_flags(entry.flags),
entry.func ? entry.func : "unknown",
@@ -317,6 +316,105 @@ mregister_table_init ()
table_count = 0;
}
/* Simple for now */
static ma_table_t *
find_location_entry (file, line)
const char *file;
int line;
{
register ma_table_t *tp, *endp;
endp = mlocation_table + location_table_count;
for (tp = mlocation_table; tp <= endp; tp++)
{
if (tp->line == line && STREQ (file, tp->file))
return tp;
}
return (ma_table_t *)NULL;
}
void
mlocation_register_alloc (file, line)
const char *file;
int line;
{
ma_table_t *lentry;
char *nfile;
if (file == 0)
{
mlocation_table[0].nalloc++;
return;
}
nfile = strrchr (file, '/');
if (nfile)
nfile++;
else
nfile = file;
lentry = find_location_entry (nfile, line);
if (lentry == 0)
{
location_table_index++;
if (location_table_index == REG_TABLE_SIZE)
location_table_index = 1; /* slot 0 reserved */
lentry = mlocation_table + location_table_index;
lentry->file = nfile;
lentry->line = line;
lentry->nalloc = 1;
if (location_table_count < REG_TABLE_SIZE)
location_table_count++; /* clamp at REG_TABLE_SIZE for now */
}
else
lentry->nalloc++;
}
static void
_location_dump_table (fp)
FILE *fp;
{
register ma_table_t *tp, *endp;
endp = mlocation_table + location_table_count;
for (tp = mlocation_table; tp < endp; tp++)
fprintf (fp, "%s:%d\t%d\n", tp->file ? tp->file : "unknown",
tp->line ? tp->line : 0,
tp->nalloc);
}
void
mlocation_dump_table ()
{
_location_dump_table (stderr);
}
#define LOCROOT "/var/tmp/maltrace/locations."
void
mlocation_write_table ()
{
FILE *fp;
char defname[sizeof (LOCROOT) + 64];
fp = _imalloc_fopen ((char *)NULL, (char *)NULL, LOCROOT, defname, sizeof (defname));
if (fp == 0)
return; /* XXX - no error message yet */
_location_dump_table (fp);
fclose (fp);
}
void
mlocation_table_init ()
{
memset (mlocation_table, 0, sizeof (ma_table_t) * REG_TABLE_SIZE);
mlocation_table[0].file = ""; /* reserve slot 0 for unknown locations */
mlocation_table[0].line = 0;
mlocation_table[0].nalloc = 0;
location_table_count = 1;
}
#endif /* MALLOC_REGISTER */
int
+11
View File
@@ -64,6 +64,17 @@ extern void mregister_describe_mem ();
extern void mregister_dump_table __P((void));
extern void mregister_table_init __P((void));
typedef struct ma_table {
char *file;
int line;
int nalloc;
} ma_table_t;
extern void mlocation_register_alloc __P((const char *, int));
extern void mlocation_table_init __P((void));
extern void mlocation_dump_table __P((void));
extern void mlocation_write_table __P((void));
/* NOTE: HASH_MIX taken from dmalloc (http://dmalloc.com) */
/*
+7 -2
View File
@@ -50,6 +50,7 @@
#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>"
#define HISTORY_QUOTE_CHARACTERS "\"'`"
#define HISTORY_EVENT_DELIMITERS "^$*%-"
#define slashify_in_quotes "\\`\"$"
@@ -62,6 +63,10 @@ static char *subst_rhs;
static int subst_lhs_len;
static int subst_rhs_len;
/* Characters that delimit history event specifications and separate event
specifications from word designators. Static for now */
static char *history_event_delimiter_chars = HISTORY_EVENT_DELIMITERS;
static char *get_history_word_specifier PARAMS((char *, char *, int *));
static int history_tokenize_word PARAMS((const char *, int));
static char **history_tokenize_internal PARAMS((const char *, int, int *));
@@ -112,7 +117,6 @@ rl_linebuf_func_t *history_inhibit_expansion_function;
/* The last string searched for by a !?string? search. */
static char *search_string;
/* The last string matched by a !?string? search. */
static char *search_match;
@@ -225,6 +229,7 @@ get_history_event (string, caller_index, delimiting_quote)
#endif /* HANDLE_MULTIBYTE */
if ((!substring_okay && (whitespace (c) || c == ':' ||
(history_event_delimiter_chars && member (c, history_event_delimiter_chars)) ||
(history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
string[i] == delimiting_quote)) ||
string[i] == '\n' ||
@@ -873,7 +878,7 @@ history_expand_internal (string, start, qc, end_index_ptr, ret_string, current_l
1) If expansions did take place
2) If the `p' modifier was given and the caller should print the result
If an error ocurred in expansion, then OUTPUT contains a descriptive
If an error occurred in expansion, then OUTPUT contains a descriptive
error message. */
#define ADD_STRING(s) \
+4 -1
View File
@@ -60,7 +60,10 @@ ansicstr (string, len, flags, sawc, rlen)
return ((char *)NULL);
#if defined (HANDLE_MULTIBYTE)
ret = (char *)xmalloc (4*len + 1);
temp = 4*len + 1;
if (temp < 12)
temp = 12; /* ensure enough for eventual u32cesc */
ret = (char *)xmalloc (temp);
#else
ret = (char *)xmalloc (2*len + 1); /* 2*len for possible CTLESC */
#endif
+1 -1
View File
@@ -236,7 +236,7 @@ u32toutf16 (c, s)
}
/* convert a single unicode-32 character into a multibyte string and put the
result in S, which must be large enough (at least MB_LEN_MAX bytes) */
result in S, which must be large enough (at least max(10,MB_LEN_MAX) bytes) */
int
u32cconv (c, s)
unsigned long c;
+2 -3
View File
@@ -4912,7 +4912,7 @@ got_token:
#endif
CHECK_FOR_RESERVED_WORD (token);
the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
the_word = alloc_word_desc ();
the_word->word = (char *)xmalloc (1 + token_index);
the_word->flags = 0;
strcpy (the_word->word, token);
@@ -6258,8 +6258,7 @@ set_line_mbstate ()
if (shell_input_line == NULL)
return;
len = strlen (shell_input_line); /* XXX - shell_input_line_len ? */
FREE (shell_input_line_property);
shell_input_line_property = (char *)xmalloc (len + 1);
shell_input_line_property = (char *)xrealloc (shell_input_line_property, len + 1);
memset (&prevs, '\0', sizeof (mbstate_t));
for (i = previ = 0; i < len; i++)
+4 -1
View File
@@ -118,10 +118,13 @@ redirection_error (temp, error)
allocname = 0;
if ((temp->rflags & REDIR_VARASSIGN) && error < 0)
filename = allocname = savestring (temp->redirector.filename->word);
else if (temp->redirector.dest < 0)
else if ((temp->rflags & REDIR_VARASSIGN) == 0 && temp->redirector.dest < 0)
/* This can happen when read_token_word encounters overflow, like in
exec 4294967297>x */
{
itrace("redirection_error: temp->redirector.dest = %d", temp->redirector.dest);
filename = _("file descriptor out of range");
}
#ifdef EBADF
/* This error can never involve NOCLOBBER */
else if (error != NOCLOBBER_REDIRECT && temp->redirector.dest >= 0 && error == EBADF)
+10 -5
View File
@@ -160,6 +160,7 @@ int autocd = 0;
This is a superset of the information provided by interactive_shell.
*/
int startup_state = 0;
int reading_shell_script = 0;
/* Special debugging helper. */
int debugging_login_shell = 0;
@@ -390,7 +391,7 @@ main (argc, argv, env)
xtrace_init ();
#if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS)
malloc_set_register (0); /* XXX - change to 1 for malloc debugging */
malloc_set_register (1); /* XXX - change to 1 for malloc debugging */
#endif
check_dev_tty ();
@@ -680,7 +681,8 @@ main (argc, argv, env)
}
#endif
cmd_init(); /* initialize the command object caches */
cmd_init (); /* initialize the command object caches */
uwp_init ();
if (command_execution_string)
{
@@ -721,7 +723,7 @@ main (argc, argv, env)
/* Bind remaining args to $1 ... $n */
arg_index = bind_args (argv, arg_index, argc, 1);
if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0 && (dollar_vars[1] || interactive_shell == 0))
if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0 && (reading_shell_script || interactive_shell == 0))
start_debugger ();
/* Do the things that should be done only for interactive shells. */
@@ -965,6 +967,7 @@ sh_exit (s)
#if defined (MALLOC_DEBUG) && defined (USING_BASH_MALLOC)
if (malloc_trace_at_exit)
trace_malloc_stats (get_name_for_error (), (char *)NULL);
/* mlocation_write_table (); */
#endif
exit (s);
@@ -1465,7 +1468,7 @@ open_shell_script (script_name)
{
e = errno;
file_error (filename);
exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT);
sh_exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT);
}
free (dollar_vars[0]);
@@ -1484,7 +1487,7 @@ open_shell_script (script_name)
errno = EINVAL;
#endif
file_error (filename);
exit (EX_NOINPUT);
sh_exit (EX_NOINPUT);
}
#if defined (ARRAY_VARS)
@@ -1586,6 +1589,8 @@ open_shell_script (script_name)
init_interactive_script ();
free (filename);
reading_shell_script = 1;
return (fd);
}
+15 -3
View File
@@ -595,6 +595,7 @@ quoted_strchr (s, c, flags)
return ((char *)NULL);
}
#if defined (INCLUDE_UNUSED)
/* Return 1 if CHARACTER appears in an unquoted portion of
STRING. Return 0 otherwise. CHARACTER must be a single-byte character. */
static int
@@ -679,6 +680,7 @@ unquoted_substring (substr, string)
}
return (0);
}
#endif
/* Most of the substitutions must be done in parallel. In order
to avoid using tons of unclear goto's, I have some functions
@@ -4435,7 +4437,7 @@ match_pattern (string, pat, mtype, sp, ep)
size_t slen, plen, mslen, mplen;
#endif
if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
if (string == 0 || pat == 0 || *pat == 0)
return (0);
#if defined (HANDLE_MULTIBYTE)
@@ -4709,7 +4711,7 @@ string_var_assignment (v, s)
val = sh_quote_reusable (s, 0);
i = var_attribute_string (v, 0, flags);
ret = (char *)xmalloc (i + strlen (val) + strlen (v->name) + 16);
ret = (char *)xmalloc (i + strlen (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES);
if (i > 0)
sprintf (ret, "declare -%s %s=%s", flags, v->name, val);
else
@@ -7001,6 +7003,7 @@ parameter_brace_substring (varname, value, ind, substr, quoted, flags)
/* */
/****************************************************************/
#if 0 /* Unused */
static int
shouldexp_replacement (s)
char *s;
@@ -7016,6 +7019,7 @@ shouldexp_replacement (s)
}
return 0;
}
#endif
char *
pat_subst (string, pat, rep, mflags)
@@ -7041,6 +7045,8 @@ pat_subst (string, pat, rep, mflags)
* with REP and return the result.
* 2. A null pattern with mtype == MATCH_END means to append REP to
* STRING and return the result.
* 3. A null STRING with a matching pattern means to append REP to
* STRING and return the result.
* These don't understand or process `&' in the replacement string.
*/
if ((pat == 0 || *pat == 0) && (mtype == MATCH_BEG || mtype == MATCH_END))
@@ -7062,11 +7068,17 @@ pat_subst (string, pat, rep, mflags)
}
return (ret);
}
else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
{
ret = (char *)xmalloc (STRLEN (rep) + 1);
strcpy (ret, rep);
return (ret);
}
ret = (char *)xmalloc (rsize = 64);
ret[0] = '\0';
for (replen = STRLEN (rep), rptr = 0, str = string;;)
for (replen = STRLEN (rep), rptr = 0, str = string; *str;)
{
if (match_pattern (str, pat, mtype, &s, &e) == 0)
break;
+1 -1
View File
@@ -1,4 +1,4 @@
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
+6 -4
View File
@@ -141,6 +141,8 @@ ok
-7
7
7
2
2
./arith1.sub: line 2: 4-- : syntax error: operand expected (error token is "- ")
./arith1.sub: line 3: 4++ : syntax error: operand expected (error token is "+ ")
./arith1.sub: line 4: 4 -- : syntax error: operand expected (error token is "- ")
@@ -235,13 +237,13 @@ ok
0, 0
0, 1
8 12
./arith.tests: line 286: ((: x=9 y=41 : syntax error in expression (error token is "y=41 ")
./arith.tests: line 290: a b: syntax error in expression (error token is "b")
./arith.tests: line 291: ((: a b: syntax error in expression (error token is "b")
./arith.tests: line 290: ((: x=9 y=41 : syntax error in expression (error token is "y=41 ")
./arith.tests: line 294: a b: syntax error in expression (error token is "b")
./arith.tests: line 295: ((: a b: syntax error in expression (error token is "b")
42
42
42
42
42
42
./arith.tests: line 302: b[c]d: syntax error in expression (error token is "d")
./arith.tests: line 306: b[c]d: syntax error in expression (error token is "d")
+4
View File
@@ -260,6 +260,10 @@ echo $(( -7 ))
echo $(( ++7 ))
echo $(( --7 ))
# combinations of expansions
echo $(( "`echo 1+1`" ))
echo $(( `echo 1+1` ))
${THIS_SH} ./arith1.sub
${THIS_SH} ./arith2.sub
${THIS_SH} ./arith3.sub
+11 -6
View File
@@ -14,9 +14,10 @@ declare -Ai chaff=([one]="10" [zero]="5" )
declare -Ar waste=([version]="4.0-devel" [source]="./assoc.tests" [lineno]="28" [pid]="42134" )
declare -A wheat=([two]="b" [three]="c" [one]="a" [zero]="0" )
declare -A chaff=([one]="10" ["hello world"]="flip" [zero]="5" )
./assoc.tests: line 38: unset: waste: cannot unset: readonly variable
./assoc.tests: line 39: chaff[*]: bad array subscript
./assoc.tests: line 40: [*]=12: invalid associative array key
./assoc.tests: line 38: waste: readonly variable
./assoc.tests: line 39: unset: waste: cannot unset: readonly variable
./assoc.tests: line 40: chaff[*]: bad array subscript
./assoc.tests: line 41: [*]=12: invalid associative array key
declare -A chaff=([one]="a" ["hello world"]="flip" )
flip
argv[1] = <a>
@@ -31,9 +32,9 @@ argv[2] = <flip>
argv[3] = <multiple>
argv[4] = <words>
argv[1] = <a flip multiple words>
./assoc.tests: line 57: declare: chaff: cannot destroy array variables in this way
./assoc.tests: line 59: chaff[*]: bad array subscript
./assoc.tests: line 60: [*]=12: invalid associative array key
./assoc.tests: line 58: declare: chaff: cannot destroy array variables in this way
./assoc.tests: line 60: chaff[*]: bad array subscript
./assoc.tests: line 61: [*]=12: invalid associative array key
declare -A wheat=([six]="6" ["foo bar"]="qux qix" )
argv[1] = <qux>
argv[2] = <qix>
@@ -190,3 +191,7 @@ declare -A foo=(["bar\${foo}bie"]="doll" )
bar
after printf
after use: 0
declare -A assoc=([0]="assoc" )
assoc
declare -A assoc=([two]="twoless" [three]="three" [one]="onemore" )
declare -Ar assoc=([two]="twoless" [three]="three" [one]="onemore" )
+19
View File
@@ -35,6 +35,7 @@ chaff[hello world]=flip
declare -p chaff
# TEST - errors
waste[stuff]=other
unset waste
chaff[*]=12
chaff=( [one]=a [*]=12 )
@@ -186,3 +187,21 @@ ${THIS_SH} ./assoc5.sub
${THIS_SH} ./assoc6.sub
${THIS_SH} ./assoc7.sub
# test converting between scalars and assoc arrays
unset assoc
assoc=assoc
declare -A assoc
declare -p assoc
echo ${assoc[@]}
# weird syntax required to append to multiple existing array elements using
# compound assignment syntax
unset assoc
declare -A assoc
assoc=( [one]=one [two]=two [three]=three )
assoc+=( [one]+=more [two]+=less )
declare -p assoc
readonly -A assoc
declare -p assoc
+42 -1
View File
@@ -194,4 +194,45 @@ scalar: 0
scalar: 1
scalar: 0
scalar: 0
./builtins.tests: line 263: exit: status: numeric argument required
all set:
one
two
f1 ()
{
echo f1
}
f2 ()
{
echo f2
}
all unset:
unset1
unset2
./builtins6.sub: line 28: declare: f1: not found
./builtins6.sub: line 28: declare: f2: not found
all reset:
one-one
two-one
f1 ()
{
echo f1
}
f2 ()
{
echo f2
}
vars unset:
unset1
unset2
f1 ()
{
echo f1
}
f2 ()
{
echo f2
}
funcs unset:
one-two
two-two
./builtins.tests: line 266: exit: status: numeric argument required
+3
View File
@@ -259,6 +259,9 @@ ${THIS_SH} ./builtins4.sub
# test behavior of set and unset array variables
${THIS_SH} ./builtins5.sub
# test behavior of unset builtin with -f and -v options
${THIS_SH} ./builtins6.sub
# this must be last -- it is a fatal error
exit status
+68
View File
@@ -0,0 +1,68 @@
f1()
{
echo f1
}
f2()
{
echo f2
}
v1=one
v2=two
echo all set:
echo ${v1-unset1}
echo ${v2-unset2}
declare -f -p f1 f2
unset v1 f1 v2 f2
echo all unset:
echo ${v1-unset1}
echo ${v2-unset2}
declare -f -p f1 f2
f1()
{
echo f1
}
f2()
{
echo f2
}
v1=one-one
v2=two-one
echo all reset:
echo ${v1-unset1}
echo ${v2-unset2}
declare -f -p f1 f2
unset -v v1 f1 v2 f2
echo vars unset:
echo ${v1-unset1}
echo ${v2-unset2}
declare -f -p f1 f2
v1=one-two
v2=two-two
unset -f v1 f1 v2 f2
echo funcs unset:
echo ${v1-unset1}
echo ${v2-unset2}
declare -f f1 f2
+4
View File
@@ -43,3 +43,7 @@ Be Conservative in what you send and Liberal in what you accept
BE CONSERVATIVE IN WHAT YOU SEND AND LIBERAL IN WHAT YOU ACCEPT
Be conservative in what you send and liberal in what you accept
BE CONSERVATIVE IN WHAT YOU SEND AND LIBERAL IN WHAT YOU ACCEPT
AcknOwlEdgEmEnt acknOwlEdgEmEnt
oeNoPHiLe OEnOphIlE
abcdexyz
ABCDEXYZ
+14
View File
@@ -97,3 +97,17 @@ echo ${TEXT^^}
echo ${TEXT2^}
echo ${TEXT2^^}
M1=${S1^^[aeiou]}
M2=${U2,,[AEIOU]}
echo ${M1} ${M1~}
echo ${M2} ${M2~~}
declare -l lower=aBcDe
lower+=XyZ
echo $lower
declare -u upper=aBcDe
upper+=xYZ
echo $upper
+1
View File
@@ -71,3 +71,4 @@ swap32_posix ()
done
}
yes
ab cde
+3
View File
@@ -217,3 +217,6 @@ unset x
# fixed after bash-4.0 released
: $(case a in a) echo ;; # comment
esac)
# recommended to be parsed as a nested comsub instead of arithsub
echo $(( echo ab cde ) )
+5
View File
@@ -27,3 +27,8 @@ ok 3
ok 4
ok 5
ok 6
xyz
\/tmp\/foo\/bar
/tmp/foo/bar
/tmp/foo/bar
/tmp/foo/bar
+1
View File
@@ -42,3 +42,4 @@ echo $(recho 'foo\
bar')
${THIS_SH} ./comsub1.sub
${THIS_SH} ./comsub2.sub
+6
View File
@@ -46,3 +46,9 @@ esac)
echo $(case a in (a) echo ok 6 # comment
;;
esac)
echo $( # we just took and pasted in some
# code from another script inside a
# command substitution
echo xyz
)
+8
View File
@@ -0,0 +1,8 @@
qpath='\/tmp\/foo\/bar'
echo "$qpath"
# it's crazy that all three of these produce the same result
echo ${qpath//\\/}
echo ${qpath//"`echo \\`"/}
echo ${qpath//`echo "\\\\\\\\"`/}
+13 -1
View File
@@ -110,4 +110,16 @@ after f
./errors3.sub: line 5: no_such_file: No such file or directory
TEST
./errors3.sub: line 7: no_such_file: No such file or directory
./errors.tests: line 271: `!!': not a valid identifier
1
2
./errors4.sub: line 7: var: readonly variable
after readonly assignment
./errors4.sub: line 13: break: x: numeric argument required
1
2
./errors4.sub: line 7: var: readonly variable
./errors5.sub: line 6: array: unbound variable
./errors5.sub: line 7: array: unbound variable
./errors5.sub: line 10: 7: unbound variable
./errors5.sub: line 11: 7: unbound variable
./errors.tests: line 275: `!!': not a valid identifier
+4
View File
@@ -262,6 +262,10 @@ echo $?
${THIS_SH} ./errors1.sub
${THIS_SH} ./errors2.sub
${THIS_SH} ./errors3.sub
${THIS_SH} ./errors4.sub
${THIS_SH} -o posix ./errors4.sub
${THIS_SH} ./errors5.sub
# this must be last!
# in posix mode, a function name must be a valid identifier
+18
View File
@@ -0,0 +1,18 @@
# test effect of assigning to readonly vars on loops and non-interactive shells
# fatal error when in posix mode
var=foo
readonly var
for num in 1 2 3 4 5; do
if [ $num -eq 3 ]; then
var=bar
fi
echo $num
done
echo after readonly assignment
# non-numeric arguments to break are fatal errors for all non-interactive shells
for f in 1 2 3 4 5
do
break x
done
echo after loop
+11
View File
@@ -0,0 +1,11 @@
array[1]=one
array[2]=two
set -u
( echo ${#array} )
( echo ${array} )
set -- 1 2 3
( echo ${#7} )
( echo ${7} )
+5
View File
@@ -4,6 +4,11 @@ argv[1] = <^?>
argv[1] = <^?>
argv[1] = <^A>
argv[1] = <^?>
argv[1] = <bar>
argv[1] = <^A>
argv[1] = <^?>
argv[1] = <^A>
argv[1] = <^?>
argv[1] = <abcdefgh>
argv[1] = <abcdefgh>
argv[1] = <abcdefgh>
+12
View File
@@ -31,6 +31,18 @@ recho `echo `
expect "<^?>"
recho `echo `
expect "bar"
recho ${foo:-"`echo bar`"}
expect "<^A>"
recho ${foo:-"`echo `"}
expect "<^?>"
recho ${foo:-"`echo `"}
expect "<^A>"
recho "`echo `"
expect "<^?>"
recho "`echo `"
# Test null strings without variable expansion
expect "<abcdefgh>"
recho abcd""efgh
+3
View File
@@ -127,3 +127,6 @@ echo '!!' \!\!
ok 1
ok 2
ok 3
echo shopt a
shopt a
echo a b c d 2 > /dev/null
+5
View File
@@ -122,3 +122,8 @@ echo ${!var2}
# Bash-2.01[.1] fails this test -- it attempts history expansion after the
# history_comment_char
echo ok 3 # !1200
shopt a b c d 2>/dev/null
echo !shopt-1
echo !shopt*
+6
View File
@@ -34,6 +34,8 @@ one
./nameref.tests: line 106: foo: readonly variable
./nameref.tests: line 103: foo: readonly variable
one
abxde
abxde
one
bar
@@ -127,3 +129,7 @@ local
./nameref8.sub: line 54: warning: x: circular name reference
./nameref8.sub: line 55: warning: x: circular name reference
x =
idx2
idX2
idx2
idX2
+8
View File
@@ -108,6 +108,13 @@ readonly foo=one
assignvar foo two three four
echo $foo
var=abcde
x=var
declare -n v=var
# these two should display the same
echo ${!x//c/x}
echo ${v//c/x}
${THIS_SH} ./nameref1.sub
${THIS_SH} ./nameref2.sub
${THIS_SH} ./nameref3.sub
@@ -116,3 +123,4 @@ ${THIS_SH} ./nameref5.sub
${THIS_SH} ./nameref6.sub
${THIS_SH} ./nameref7.sub
${THIS_SH} ./nameref8.sub
${THIS_SH} ./nameref9.sub
+8
View File
@@ -0,0 +1,8 @@
arr=( idx1 idx2 )
i='arr[1]'
echo ${!i}
echo ${!i/x/X}
typeset -n f='arr[1]'
echo ${f}
echo ${f/x/X}
+20 -13
View File
@@ -59,8 +59,15 @@ argv[1] = <4>
argv[1] = <op>
argv[1] = <abcdefghijklmnop>
argv[1] = <abcdefghijklmnop>
./new-exp.tests: line 172: ABX: unbound variable
./new-exp.tests: line 176: $6: cannot assign in this way
argv[1] = <a>
argv[2] = <b>
argv[3] = <c>
argv[4] = <d>
argv[1] = <a>
argv[2] = <b c>
argv[3] = <d>
./new-exp.tests: line 180: ABX: unbound variable
./new-exp.tests: line 184: $6: cannot assign in this way
argv[1] = <xxcde>
argv[1] = <axxde>
argv[1] = <abxyz>
@@ -169,7 +176,7 @@ this is test 2
./new-exp2.sub: line 42: 1111111111111111111111: command not found
argv[1] = <6>
./new-exp.tests: line 277: ${#:}: bad substitution
./new-exp.tests: line 285: ${#:}: bad substitution
argv[1] = <'>
argv[1] = <">
argv[1] = <"hello">
@@ -398,13 +405,13 @@ argv[6] = <w>
argv[7] = <x>
argv[8] = <y>
argv[9] = <z>
./new-exp.tests: line 482: $9: unbound variable
./new-exp.tests: line 483: 9: unbound variable
./new-exp.tests: line 484: UNSET: unbound variable
./new-exp.tests: line 485: UNSET: unbound variable
./new-exp.tests: line 486: UNSET: unbound variable
./new-exp.tests: line 487: UNSET: unbound variable
./new-exp.tests: line 488: UNSET: unbound variable
./new-exp.tests: line 490: $9: unbound variable
./new-exp.tests: line 491: 9: unbound variable
./new-exp.tests: line 492: UNSET: unbound variable
./new-exp.tests: line 493: UNSET: unbound variable
./new-exp.tests: line 494: UNSET: unbound variable
./new-exp.tests: line 495: UNSET: unbound variable
./new-exp.tests: line 496: UNSET: unbound variable
argv[1] = <5>
argv[1] = <#>
argv[1] = <#>
@@ -433,7 +440,7 @@ Case05---3---A:B:C---
Case06---1---A B C::---
Case07---3---A:B:C---
Case08---3---A:B:C---
./new-exp.tests: line 508: ${$(($#-1))}: bad substitution
./new-exp.tests: line 516: ${$(($#-1))}: bad substitution
argv[1] = <a>
argv[2] = <b>
argv[3] = <c>
@@ -450,7 +457,7 @@ argv[1] = <a>
argv[1] = <a>
argv[2] = <b>
argv[1] = <>
./new-exp.tests: line 527: $(($# - 2)): substring expression < 0
./new-exp.tests: line 535: $(($# - 2)): substring expression < 0
argv[1] = <bin>
argv[2] = <bin>
argv[3] = <ucb>
@@ -614,4 +621,4 @@ a b c d e
a5b
argv[1] = </>
argv[1] = </>
./new-exp.tests: line 587: ABXD: parameter unset
./new-exp.tests: line 595: ABXD: parameter unset
+8
View File
@@ -167,6 +167,14 @@ recho ${a-$z}
expect nothing
recho ${!1-$z}
set -- a 'b c' d
unset foo
foo=@
expect '<a> <b> <c> <d>'
recho ${!foo}
expect '<a> <b c> <d>'
recho "${!foo}"
set -u
expect $0: ABX: unbound variable
( recho ${ABX} )
+3
View File
@@ -76,6 +76,9 @@ declare -ar myvar=([0]="0")
declare -ir myvar="1"
declare -rx tempvar1='foo'
declare -rx tempvar2='qux'
./varenv7.sub: line 44: local: var: readonly variable
inside: outside
outside: outside
a=z
a=b
a=z
+13
View File
@@ -35,3 +35,16 @@ echo ${tempvar1@A}
tempvar2=bar declare -r tempvar2=qux
echo ${tempvar2@A}
unset foo
readonly var=outside
func()
{
local var=inside
echo "inside: $var"
}
func
echo outside: $var
+11
View File
@@ -90,3 +90,14 @@ ok 1
./vredir6.sub: redirection error: cannot duplicate fd: Invalid argument
./vredir6.sub: line 13: /dev/null: Invalid argument
unset
12 10
a
a
swizzle is a function
swizzle ()
{
exec {fd[0]}<&0;
exec {fd[1]}>&1;
exec {stdin}<&${fd[0]}-;
exec {stdout}>&${fd[1]}-
}
+2
View File
@@ -43,4 +43,6 @@ ${THIS_SH} ./vredir5.sub
${THIS_SH} ./vredir6.sub
${THIS_SH} ./vredir7.sub
exit 0
+23
View File
@@ -0,0 +1,23 @@
swizzle()
{
exec {fd[0]}<&0
exec {fd[1]}>&1
exec {stdin}<&${fd[0]}-
exec {stdout}>&${fd[1]}-
}
swizzle
echo $stdin $stdout
read line <&$stdin <<EOF
a
EOF
echo $line
echo $line >&$stdout
type swizzle
exit 0
+17 -1
View File
@@ -49,6 +49,7 @@
#include "sig.h"
#include "quit.h"
#include "error.h" /* for internal_warning */
#include "ocache.h"
/* Structure describing a saved variable and the value to restore it to. */
typedef struct {
@@ -75,7 +76,6 @@ typedef union uwp {
} sv;
} UNWIND_ELT;
static void without_interrupts __P((VFunction *, char *, char *));
static void unwind_frame_discard_internal __P((char *, char *));
static void unwind_frame_run_internal __P((char *, char *));
@@ -88,8 +88,24 @@ static void unwind_protect_mem_internal __P((char *, char *));
static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
/* Allocating from a cache of unwind-protect elements */
#define UWCACHESIZE 128
sh_obj_cache_t uwcache = {0, 0, 0};
#if 0
#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
#define uwpfree(elt) free(elt)
#else
#define uwpalloc(elt) ocache_alloc (uwcache, UNWIND_ELT, elt)
#define uwpfree(elt) ocache_free (uwcache, UNWIND_ELT, elt)
#endif
void
uwp_init ()
{
ocache_create (uwcache, UNWIND_ELT, UWCACHESIZE);
}
/* Run a function without interrupts. This relies on the fact that the
FUNCTION cannot change the value of interrupt_immediately. (I.e., does
+2
View File
@@ -21,6 +21,8 @@
#if !defined (_UNWIND_PROT_H)
#define _UNWIND_PROT_H
extern void uwp_init __P((void));
/* Run a function without interrupts. */
extern void begin_unwind_frame __P((char *));
extern void discard_unwind_frame __P((char *));