diff -pru bash/variables.c bash.orig/variables.c --- bash/variables.c 2001-08-21 21:27:13.000000000 -0700 +++ bash.orig/variables.c 2014-10-01 14:15:09.201062493 -0700 @@ -61,6 +61,11 @@ #if defined (PROGRAMMABLE_COMPLETION) # include "pcomplete.h" #endif + +#define BASHFUNC_PREFIX "BASH_FUNC_" +#define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */ +#define BASHFUNC_SUFFIX "%%" +#define BASHFUNC_SUFFLEN 2 /* == strlen(BASHFUNC_SUFFIX) */ /* Variables used here and defined in other files. */ extern int posixly_correct; @@ -181,33 +186,41 @@ initialize_shell_variables (env, privmod char_index == strlen (name) */ /* If exported function, define it now. */ - if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4)) - { - string_length = strlen (string); - temp_string = xmalloc (3 + string_length + char_index); - - strcpy (temp_string, name); - temp_string[char_index] = ' '; - strcpy (temp_string + char_index + 1, string); + if (privmode == 0 && read_but_dont_execute == 0 && + STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) && + STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) && + STREQN ("() {", string, 4)) + { + size_t namelen; + char *tname; /* desired imported function name */ + + namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN; + + tname = name + BASHFUNC_PREFLEN; /* start of func name */ + tname[namelen] = '\0'; /* now tname == func name */ - parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST); + string_length = strlen (string); + temp_string = xmalloc (namelen + string_length + 2); - /* Ancient backwards compatibility. Old versions of bash exported - functions like name()=() {...} */ - if (name[char_index - 1] == ')' && name[char_index - 2] == '(') - name[char_index - 2] = '\0'; + memcpy (temp_string, tname, namelen); + temp_string[namelen] = ' '; + memcpy (temp_string + namelen + 1, string, string_length + 1); + + /* Don't import function names that are invalid identifiers from the + environment. */ + if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname))) + parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); - if (temp_var = find_function (name)) + if (temp_var = find_function (tname)) { VSETATTR (temp_var, (att_exported|att_imported)); array_needs_making = 1; } else - report_error ("error importing function definition for `%s'", name); + report_error ("error importing function definition for `%s'", tname); - /* ( */ - if (name[char_index - 1] == ')' && name[char_index - 2] == '\0') - name[char_index - 2] = '('; /* ) */ + /* Restore original suffic */ + tname[namelen] = BASHFUNC_SUFFIX[0]; } #if defined (ARRAY_VARS) # if 0 @@ -2501,21 +2514,42 @@ all_variables_matching_prefix (prefix) } static inline char * -mk_env_string (name, value) +mk_env_string (name, value, isfunc) char *name, *value; + int isfunc; { - int name_len, value_len; - char *p; + size_t name_len, value_len; + char *p, *q; name_len = strlen (name); value_len = STRLEN (value); - p = xmalloc (2 + name_len + value_len); - strcpy (p, name); - p[name_len] = '='; + + /* If we are exporting a shell function, construct the encoded function + name. */ + if (isfunc && value) + { + p = xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2); + q = p; + memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN); + q += BASHFUNC_PREFLEN; + memcpy (q, name, name_len); + q += name_len; + memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN); + q += BASHFUNC_SUFFLEN; + } + else + { + p = xmalloc (2 + name_len + value_len); + memcpy (p, name, name_len); + q = p + name_len; + } + + q[0] = '='; if (value && *value) - strcpy (p + name_len + 1, value); + memcpy (q + 1, value, value_len + 1); else - p[name_len + 1] = '\0'; + q[1] = '\0'; + return (p); } @@ -2597,7 +2631,7 @@ make_var_array (hashed_vars) /* Gee, I'd like to get away with not using savestring() if we're using the cached exportstr... */ list[list_index] = USE_EXPORTSTR ? savestring (value) - : mk_env_string (var->name, value); + : mk_env_string (var->name, value, function_p (var)); if (USE_EXPORTSTR == 0 && function_p (var)) { @@ -2661,7 +2695,7 @@ assign_in_env (string) free (temp); } - temp = mk_env_string (name, value); + temp = mk_env_string (name, value, 0); FREE (value); free (name); @@ -2739,7 +2773,7 @@ bind_name_in_env_array (name, value, arr { if (STREQN (array[i], name, l) && array[i][l] == '=') { - new_env_string = mk_env_string (name, value); + new_env_string = mk_env_string (name, value, 0); temp = shell_var_from_env_string (name, new_env_string, l); diff -pru bash/builtins/common.h bash.orig/builtins/common.h --- bash/builtins/common.h 2001-08-21 21:27:15.000000000 -0700 +++ bash.orig/builtins/common.h 2014-09-30 13:30:14.983872164 -0700 @@ -29,6 +29,9 @@ #define SEVAL_NONINT 0x01 #define SEVAL_INTERACT 0x02 #define SEVAL_NOHIST 0x04 +#define SEVAL_FUNCDEF 0x080 /* only allow function definitions */ +#define SEVAL_ONECMD 0x100 /* only allow a single command */ + /* Functions from common.c */ extern void builtin_error __P((const char *, ...)); diff -pru bash/builtins/evalstring.c bash.orig/builtins/evalstring.c --- bash/builtins/evalstring.c 2001-08-21 21:27:15.000000000 -0700 +++ bash.orig/builtins/evalstring.c 2014-09-30 13:30:14.983872164 -0700 @@ -206,7 +206,16 @@ parse_and_execute (string, from_file, fl else if (command = global_command) { struct fd_bitmap *bitmap; - + + if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def) + { + internal_warning ("%s: ignoring function definition attempt", from_file); + should_jump_to_top_level = 0; + last_result = last_command_exit_value = EX_BADUSAGE; + break; + } + + bitmap = new_fd_bitmap (FD_BITMAP_SIZE); begin_unwind_frame ("pe_dispose"); add_unwind_protect (dispose_fd_bitmap, bitmap); @@ -258,6 +267,10 @@ parse_and_execute (string, from_file, fl dispose_command (command); dispose_fd_bitmap (bitmap); discard_unwind_frame ("pe_dispose"); + + if (flags & SEVAL_ONECMD) + break; + } } else diff -pru bash/parse.y bash.orig/parse.y --- bash/parse.y 2001-08-21 21:27:13.000000000 -0700 +++ bash.orig/parse.y 2014-10-01 14:38:30.289422313 -0700 @@ -161,8 +161,13 @@ static char *current_decoded_prompt; int current_command_line_count; /* Variables to manage the task of reading here documents, because we need to + +static void push_heredoc __P((REDIRECT *)); +static char *mk_alexpansion __P((char *)); defer the reading until after a complete command has been collected. */ -static REDIRECT *redir_stack[10]; +#define HEREDOC_MAX 16 + +static REDIRECT *redir_stack[HEREDOC_MAX]; int need_here_doc; /* Where shell input comes from. History expansion is performed on each @@ -318,13 +323,13 @@ redirection: '>' WORD { redir.filename = $2; $$ = make_redirection (0, r_reading_until, redir); - redir_stack[need_here_doc++] = $$; + push_heredoc ($$); } | NUMBER LESS_LESS WORD { redir.filename = $3; $$ = make_redirection ($1, r_reading_until, redir); - redir_stack[need_here_doc++] = $$; + push_heredoc ($$); } | LESS_AND NUMBER { @@ -371,14 +376,14 @@ redirection: '>' WORD redir.filename = $2; $$ = make_redirection (0, r_deblank_reading_until, redir); - redir_stack[need_here_doc++] = $$; + push_heredoc ($$); } | NUMBER LESS_LESS_MINUS WORD { redir.filename = $3; $$ = make_redirection ($1, r_deblank_reading_until, redir); - redir_stack[need_here_doc++] = $$; + push_heredoc ($$); } | GREATER_AND '-' { @@ -1916,6 +1921,21 @@ yylex () which allow ESAC to be the next one read. */ static int esacs_needed_count; +static void +push_heredoc (r) + REDIRECT *r; +{ + if (need_here_doc >= HEREDOC_MAX) + { + last_command_exit_value = EX_BADUSAGE; + need_here_doc = 0; + report_syntax_error ("maximum here-document count exceeded"); + reset_parser (); + exit_shell (last_command_exit_value); + } + redir_stack[need_here_doc++] = r; +} + void gather_here_documents () { @@ -2182,6 +2202,8 @@ reset_parser () FREE (word_desc_to_read); word_desc_to_read = (WORD_DESC *)NULL; + eol_ungetc_lookahead = 0; + last_read_token = '\n'; token_to_read = '\n'; }