From: Chet Ramey Date: Mon, 27 Feb 2023 15:55:06 +0000 (-0500) Subject: local variables no longer modify external variables if the variable is supplied as... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=349e21043e362914551277728159f8e55350bad7;p=thirdparty%2Fbash.git local variables no longer modify external variables if the variable is supplied as a variable assignment preceding a function call; assignments in compound assignment statements don't undergo brace expansion --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 34539b3be..d05a91f4c 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -5437,3 +5437,40 @@ jobs.c - wait_for: if we're checking for window size changes, allow checks during trap commands while readline is active or `bind -x' command execution. Fix from Koichi Murase + + 2/22 + ---- +jobs.c + - wait_for: check for window size changes during programmable completion + + 2/23 + ---- +execute_cmd.c,input.c,jobs.c,nojobs.c,parse.y,redir.c,shell.c +builtins/{exec.def,read.def} +input.h + - BUFFERED_INPUT: preprocessor #define is gone, this code is now + unconditional + + 2/24 + ---- +builtins/declare.def + - declare_internal: set the att_propagate flag on a variable that is + marked as att_tempvar only if it's *not* marked att_local. The + effect is that local variables with the same name as variables in + the temporary environment are not propagated to the previous scope. + From a report by Voldemar Lazarev + that prompted a bug-bash discussion + +builtins/setattr.def + - set_var_attribute: don't set local variables for which we are setting + export or readonly to propagate back to the previous context, but + make sure we preserve posix semantics + +parse.y + - read_token_word: if we're parsing the words of a compound assignment + (parser_state & PST_COMPASSIGN), and we have a valid assignment + statement as a word ([sub]=value), set W_NOBRACE in the word so we + don't try and perform brace expansion on it. This makes ( [sub]=word ) + closer to name[sub]=word. + From a report by Ilkka Virta back in July, 2020: + https://lists.gnu.org/archive/html/bug-bash/2020-07/msg00133.html diff --git a/MANIFEST b/MANIFEST index 1e9685d3b..436947247 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1540,6 +1540,7 @@ tests/varenv19.sub f tests/varenv20.sub f tests/varenv21.sub f tests/varenv22.sub f +tests/varenv23.sub f tests/version f tests/version.mini f tests/vredir.tests f diff --git a/builtins/declare.def b/builtins/declare.def index 28100de1b..41c11e1f8 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -990,7 +990,10 @@ restart_new_var_name: /* If we found this variable in the temporary environment, as with `var=value declare -x var', make sure it is treated identically to `var=value export var'. Do the same for `declare -r' and - `readonly'. Preserve the attributes, except for att_tempvar. */ + `readonly'. Preserve the attributes, except for att_tempvar. + This doesn't happen in functions, since declare in shell functions + always creates local variables (that inherit their value from the + tempenv variable). We don't check variable_context; maybe we should. */ /* XXX -- should this create a variable in the global scope, or modify the local variable flags? ksh93 has it modify the global scope. @@ -1001,6 +1004,7 @@ restart_new_var_name: SHELL_VAR *tv; char *tvalue; + /* Temporary environment? Or in the local variable context? */ tv = find_tempenv_variable (name_cell (var)); if (tv) { @@ -1009,12 +1013,15 @@ restart_new_var_name: if (tv) { tv->attributes |= var->attributes & ~att_tempvar; - if (tv->context > 0) + if (tv->context > 0 && local_p (var) == 0) /* just paranoia here */ VSETATTR (tv, att_propagate); } free (tvalue); } - VSETATTR (var, att_propagate); + /* XXX - don't propagate local variables back to a previous scope, + even in posix mode. */ + if (local_p (var) == 0) + VSETATTR (var, att_propagate); } /* Turn on nameref attribute we deferred above. */ diff --git a/builtins/exec.def b/builtins/exec.def index b0638dac3..54dc66459 100644 --- a/builtins/exec.def +++ b/builtins/exec.def @@ -223,10 +223,8 @@ exec_builtin (WORD_LIST *list) default_tty_job_signals (); /* undo initialize_job_signals */ #endif /* JOB_CONTROL */ -#if defined (BUFFERED_INPUT) if (default_buffered_input >= 0) sync_buffered_stream (default_buffered_input); -#endif exit_value = shell_execve (command, args, env); diff --git a/builtins/read.def b/builtins/read.def index 7e122c3bd..e0f73749e 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -103,9 +103,7 @@ $END #include #endif -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif +#include "input.h" #include "shmbutil.h" #include "timer.h" @@ -425,10 +423,8 @@ read_builtin (WORD_LIST *list) begin_unwind_frame ("read_builtin"); -#if defined (BUFFERED_INPUT) if (interactive == 0 && default_buffered_input >= 0 && fd_is_bash_input (fd)) sync_buffered_stream (default_buffered_input); -#endif #if 1 input_is_tty = isatty (fd); diff --git a/builtins/setattr.def b/builtins/setattr.def index 0f0dbf2c7..4520c9e55 100644 --- a/builtins/setattr.def +++ b/builtins/setattr.def @@ -574,6 +574,8 @@ show_func_attributes (char *name, int nodefs) return (1); } +/* This is only called by readonly/export, so we can implement posix-mode + semantics for special variables. */ void set_var_attribute (char *name, int attribute, int undo) { @@ -584,6 +586,7 @@ set_var_attribute (char *name, int attribute, int undo) var = find_variable (name); else { + /* var=value readonly var */ tv = find_tempenv_variable (name); /* XXX -- need to handle case where tv is a temp variable in a function-scope context, since function_env has been merged into @@ -645,7 +648,7 @@ set_var_attribute (char *name, int attribute, int undo) if (var) VSETATTR (var, att_invisible); } - else if (var->context != 0) + else if (var->context != 0 && local_p (var) == 0) VSETATTR (var, att_propagate); } } diff --git a/config-top.h b/config-top.h index 05b78a359..f2ebc6716 100644 --- a/config-top.h +++ b/config-top.h @@ -31,11 +31,6 @@ error messages about multiple directory arguments to `cd'. */ #define CD_COMPLAINS -/* Define BUFFERED_INPUT if you want the shell to do its own input - buffering, rather than using stdio. Do not undefine this; it's - required to preserve semantics required by POSIX. */ -#define BUFFERED_INPUT - /* Define ONESHOT if you want sh -c 'command' to avoid forking to execute `command' whenever possible. This is a big efficiency improvement. */ #define ONESHOT diff --git a/doc/bash.1 b/doc/bash.1 index 587a94d77..80b5b63e2 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -2754,10 +2754,14 @@ Arrays are assigned to using compound assignments of the form \fIname\fP=\fB(\fPvalue\fI1\fP ... value\fIn\fP\fB)\fP, where each \fIvalue\fP may be of the form [\fIsubscript\fP]=\fIstring\fP. Indexed array assignments do not require anything but \fIstring\fP. -Each \fIvalue\fP in the list is expanded using all the shell expansions +Each \fIvalue\fP in the list is expanded using the shell expansions described below under .SM -.BR EXPANSION . +.BR EXPANSION , +but \fIvalue\fPs that are valid variable assignments +including the brackets and subscript do not undergo +brace expansion and word splitting, as with individual +variable assignments. When assigning to indexed arrays, if the optional brackets and subscript are supplied, that index is assigned to; otherwise the index of the element assigned is the last index assigned diff --git a/doc/bashref.texi b/doc/bashref.texi index 9eeab7359..727d23772 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -7741,8 +7741,12 @@ the optional subscript is supplied, that index is assigned to; otherwise the index of the element assigned is the last index assigned to by the statement plus one. Indexing starts at zero. -Each @var{value} in the list undergoes all the shell expansions -described above (@pxref{Shell Expansions}). +Each @var{value} in the list undergoes the shell expansions +described above (@pxref{Shell Expansions}), +but @var{value}s that are valid variable assignments +including the brackets and subscript do not undergo +brace expansion and word splitting, as with individual +variable assignments. When assigning to an associative array, the words in a compound assignment may be either assignment statements, for which the subscript is required, diff --git a/execute_cmd.c b/execute_cmd.c index 185404099..16d5328ad 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -1,6 +1,6 @@ /* execute_cmd.c -- Execute a COMMAND structure. */ -/* 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. @@ -90,9 +90,7 @@ extern int errno; #include #include -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif +#include "input.h" #if defined (ALIAS) # include "alias.h" @@ -1626,10 +1624,8 @@ execute_in_subshell (COMMAND *command, int asynchronous, int pipe_in, int pipe_o if (should_redir_stdin && stdin_redir == 0) async_redirect_stdin (); -#if defined (BUFFERED_INPUT) /* In any case, we are not reading our command input from stdin. */ default_buffered_input = -1; -#endif /* We can't optimize away forks if one of the commands executed by the subshell sets an exit trap, so we set CMD_NO_FORK for simple commands diff --git a/input.c b/input.c index 73ffa3ec7..155fd3699 100644 --- a/input.c +++ b/input.c @@ -1,6 +1,6 @@ /* input.c -- functions to perform buffered input with synchronization. */ -/* Copyright (C) 1992-2022 Free Software Foundation, Inc. +/* Copyright (C) 1992-2023 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -124,8 +124,6 @@ ungetc_with_restart (int c, FILE *stream) return c; } -#if defined (BUFFERED_INPUT) - /* A facility similar to stdio, but input-only. */ #if defined (USING_BASH_MALLOC) @@ -653,4 +651,3 @@ main(int argc, char **argv) exit(0); } #endif /* TEST */ -#endif /* BUFFERED_INPUT */ diff --git a/input.h b/input.h index 09a42119f..a1fa7219a 100644 --- a/input.h +++ b/input.h @@ -1,6 +1,6 @@ /* input.h -- Structures and unions used for reading input. */ -/* Copyright (C) 1993-2022 Free Software Foundation, Inc. +/* Copyright (C) 1993-2023 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -28,8 +28,6 @@ typedef int sh_cunget_func_t (int); /* sh_intfunc_t */ enum stream_type {st_none, st_stdin, st_stream, st_string, st_bstream}; -#if defined (BUFFERED_INPUT) - /* Possible values for b_flag. */ #undef B_EOF #undef B_ERROR /* There are some systems with this define */ @@ -71,14 +69,10 @@ extern int bash_input_fd_changed; #define bclearerror(bp) ((bp)->b_flag &= ~(B_ERROR|B_EOF)) -#endif /* BUFFERED_INPUT */ - typedef union { FILE *file; char *string; -#if defined (BUFFERED_INPUT) int buffered_fd; -#endif } INPUT_STREAM; typedef struct { @@ -114,7 +108,6 @@ extern void restore_token_state (int *); extern int getc_with_restart (FILE *); extern int ungetc_with_restart (int, FILE *); -#if defined (BUFFERED_INPUT) /* Functions from input.c. */ extern int fd_is_bash_input (int); extern int set_bash_input_fd (int); @@ -132,6 +125,5 @@ extern int sync_buffered_stream (int); extern int buffered_getchar (void); extern int buffered_ungetchar (int); extern void with_input_from_buffered_stream (int, char *); -#endif /* BUFFERED_INPUT */ #endif /* _INPUT_H_ */ diff --git a/jobs.c b/jobs.c index c0cae92df..1c225aa6c 100644 --- a/jobs.c +++ b/jobs.c @@ -49,9 +49,7 @@ #include #endif -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif +#include "input.h" /* Need to include this up here for *_TTY_DRIVER definitions. */ #include "shtty.h" @@ -2091,15 +2089,12 @@ make_child (char *command, int flags) async_p = (flags & FORK_ASYNC); forksleep = 1; -#if defined (BUFFERED_INPUT) /* If default_buffered_input is active, we are reading a script. If the command is asynchronous, we have already duplicated /dev/null as fd 0, but have not changed the buffered stream corresponding to the old fd 0. We don't want to sync the stream in this case. */ - if (default_buffered_input != -1 && - (!async_p || default_buffered_input > 0)) + if (default_buffered_input != -1 && (!async_p || default_buffered_input > 0)) sync_buffered_stream (default_buffered_input); -#endif /* BUFFERED_INPUT */ /* Create the child, handle severe errors. Retry on EAGAIN. */ while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX) @@ -2153,12 +2148,11 @@ make_child (char *command, int flags) child process, go back and change callers who free `command' in the child process when this returns. */ mypid = getpid (); -#if defined (BUFFERED_INPUT) + /* Close default_buffered_input if it's > 0. We don't close it if it's 0 because that's the file descriptor used when redirecting input, and it's wrong to close the file in that case. */ unset_bash_input (0); -#endif /* BUFFERED_INPUT */ CLRINTERRUPT; /* XXX - children have their own interrupt state */ @@ -3057,17 +3051,17 @@ if (job == NO_JOB) } else #if defined (READLINE) - /* We don't want to do this if we are running a process during - programmable completion, but we do want to handle window size - changes for traps while readline is active or a command bound - to `bind -x'. */ - if (RL_ISSTATE (RL_STATE_COMPLETING) == 0) - if (RL_ISSTATE(RL_STATE_DISPATCHING|RL_STATE_TERMPREPPED) != 0) - { - if (check_window_size) - get_new_window_size (0, (int *)0, (int *)0); - } - else + /* We don't want to get the entire tty state if we are running + while readline is active or has changed the terminal, but we + can handle window size changes during programmable completion, + traps while readline is active, or a command bound using + `bind -x'. */ + if (RL_ISSTATE(RL_STATE_COMPLETING|RL_STATE_DISPATCHING|RL_STATE_TERMPREPPED) != 0) + { + if (check_window_size) + get_new_window_size (0, (int *)0, (int *)0); + } + else #endif get_tty_state (); diff --git a/nojobs.c b/nojobs.c index 4374d2630..6ca05ba1b 100644 --- a/nojobs.c +++ b/nojobs.c @@ -3,7 +3,7 @@ /* This file works under BSD, System V, minix, and Posix systems. It does not implement job control. */ -/* 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. @@ -34,9 +34,7 @@ #include #include -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif +#include "input.h" /* Need to include this up here for *_TTY_DRIVER definitions. */ #include "shtty.h" @@ -485,14 +483,12 @@ make_child (char *command, int flags) async_p = (flags & FORK_ASYNC); start_pipeline (); -#if defined (BUFFERED_INPUT) /* If default_buffered_input is active, we are reading a script. If the command is asynchronous, we have already duplicated /dev/null as fd 0, but have not changed the buffered stream corresponding to the old fd 0. We don't want to sync the stream in this case. */ if (default_buffered_input != -1 && (!async_p || default_buffered_input > 0)) sync_buffered_stream (default_buffered_input); -#endif /* BUFFERED_INPUT */ /* Block SIGTERM here and unblock in child after fork resets the set of pending signals */ @@ -540,9 +536,7 @@ make_child (char *command, int flags) if (pid == 0) { -#if defined (BUFFERED_INPUT) unset_bash_input (0); -#endif /* BUFFERED_INPUT */ CLRINTERRUPT; /* XXX - children have their own interrupt state */ diff --git a/parse.y b/parse.y index 2bfc0c666..231cde6d2 100644 --- a/parse.y +++ b/parse.y @@ -1509,7 +1509,6 @@ yy_ungetc (int c) return (*(bash_input.ungetter)) (c); } -#if defined (BUFFERED_INPUT) #ifdef INCLUDE_UNUSED int input_file_descriptor (void) @@ -1526,7 +1525,6 @@ input_file_descriptor (void) } } #endif -#endif /* BUFFERED_INPUT */ /* **************************************************************** */ /* */ @@ -1756,9 +1754,7 @@ typedef struct stream_saver { struct stream_saver *next; BASH_INPUT bash_input; int line; -#if defined (BUFFERED_INPUT) BUFFERED_STREAM *bstream; -#endif /* BUFFERED_INPUT */ } STREAM_SAVER; /* The globally known line number. */ @@ -1781,13 +1777,11 @@ push_stream (int reset_lineno) xbcopy ((char *)&bash_input, (char *)&(saver->bash_input), sizeof (BASH_INPUT)); -#if defined (BUFFERED_INPUT) saver->bstream = (BUFFERED_STREAM *)NULL; /* If we have a buffered stream, clear out buffers[fd]. */ if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0) saver->bstream = set_buffered_stream (bash_input.location.buffered_fd, (BUFFERED_STREAM *)NULL); -#endif /* BUFFERED_INPUT */ saver->line = line_number; bash_input.name = (char *)NULL; @@ -1816,7 +1810,6 @@ pop_stream (void) saver->bash_input.name, saver->bash_input.location); -#if defined (BUFFERED_INPUT) /* If we have a buffered stream, restore buffers[fd]. */ /* If the input file descriptor was changed while this was on the save stack, update the buffered fd to the new file descriptor and @@ -1836,7 +1829,6 @@ pop_stream (void) /* XXX could free buffered stream returned as result here. */ set_buffered_stream (bash_input.location.buffered_fd, saver->bstream); } -#endif /* BUFFERED_INPUT */ line_number = saver->line; @@ -2334,11 +2326,7 @@ shell_getc (int remove_quoted_newline) QUIT; last_was_backslash = 0; - if (sigwinch_received) - { - sigwinch_received = 0; - get_new_window_size (0, (int *)0, (int *)0); - } + CHECK_WINCH; if (eol_ungetc_lookahead) { @@ -2458,7 +2446,6 @@ shell_getc (int remove_quoted_newline) if (i == 0) shell_input_line_terminator = EOF; -#if defined (BUFFERED_INPUT) if (i == 0 && bash_input.type == st_bstream) { BUFFERED_STREAM *bp; @@ -2467,9 +2454,8 @@ shell_getc (int remove_quoted_newline) shell_input_line_terminator = READERR; } else -#endif - if (i == 0 && interactive_shell == 0 && bash_input.type == st_stream && ferror (stdin)) - shell_input_line_terminator = READERR; + if (i == 0 && interactive_shell == 0 && bash_input.type == st_stream && ferror (stdin)) + shell_input_line_terminator = READERR; /* If we want to make read errors cancel execution of any partial line, take out the checks for i == 0 above and set i = 0 if @@ -5456,7 +5442,7 @@ got_token: { the_word->flags |= W_NOSPLIT; if (parser_state & PST_COMPASSIGN) - the_word->flags |= W_NOGLOB; /* XXX - W_NOBRACE? */ + the_word->flags |= W_NOGLOB|W_NOBRACE; } } diff --git a/quit.h b/quit.h index 2d6dca4e3..44d908283 100644 --- a/quit.h +++ b/quit.h @@ -73,4 +73,14 @@ extern volatile sig_atomic_t terminating_signal; do { \ if (sigterm_received) termsig_handler (SIGTERM); \ } while (0) + +#define CHECK_WINCH \ +do { \ + if (sigwinch_received) \ + { \ + sigwinch_received = 0; \ + get_new_window_size (0, (int *)0, (int *)0); \ + } \ +} while (0) + #endif /* _QUIT_H_ */ diff --git a/redir.c b/redir.c index f3407c69a..804d9b827 100644 --- a/redir.c +++ b/redir.c @@ -1,6 +1,6 @@ /* redir.c -- Functions to perform input and output redirection. */ -/* Copyright (C) 1997-2022 Free Software Foundation, Inc. +/* Copyright (C) 1997-2023 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -54,9 +54,7 @@ extern int errno; #include "redir.h" #include "trap.h" -#if defined (BUFFERED_INPUT) -# include "input.h" -#endif +#include "input.h" #include "builtins/pipesize.h" @@ -936,11 +934,9 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp) REDIRECTION_ERROR (r, errno, fd); } -#if defined (BUFFERED_INPUT) /* inhibit call to sync_buffered_stream() for async processes */ if (redirector != 0 || (subshell_environment & SUBSHELL_ASYNC) == 0) check_bash_input (redirector); -#endif /* Make sure there is no pending output before we change the state of the underlying file descriptor, since the builtins use stdio @@ -971,13 +967,11 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp) return (errno); } -#if defined (BUFFERED_INPUT) /* Do not change the buffered stream for an implicit redirection of /dev/null to fd 0 for asynchronous commands without job control (r_inputa_direction). */ if (ri == r_input_direction || ri == r_input_output) duplicate_buffered_stream (fd, redirector); -#endif /* BUFFERED_INPUT */ /* * If we're remembering, then this is the result of a while, for @@ -995,11 +989,9 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp) if (fd != redirector) { -#if defined (BUFFERED_INPUT) if (INPUT_REDIRECT (ri)) close_buffered_fd (fd); else -#endif /* !BUFFERED_INPUT */ close (fd); /* Don't close what we just opened! */ } @@ -1057,9 +1049,8 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp) REDIRECTION_ERROR (r, errno, fd); } -#if defined (BUFFERED_INPUT) check_bash_input (redirector); -#endif + if (redirect->rflags & REDIR_VARASSIGN) { if ((r = redir_varassign (redirect, redirector)) < 0) @@ -1076,20 +1067,14 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp) return (r); } -#if defined (BUFFERED_INPUT) duplicate_buffered_stream (fd, redirector); -#endif if ((flags & RX_CLEXEC) && (redirector > 2)) SET_CLOSE_ON_EXEC (redirector); } if (fd != redirector) -#if defined (BUFFERED_INPUT) close_buffered_fd (fd); -#else - close (fd); -#endif } break; @@ -1131,11 +1116,11 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp) REDIRECTION_ERROR (r, errno, -1); } } -#if defined (BUFFERED_INPUT) + /* inhibit call to sync_buffered_stream() for async processes */ if (redirector != 0 || (subshell_environment & SUBSHELL_ASYNC) == 0) check_bash_input (redirector); -#endif + if (redirect->rflags & REDIR_VARASSIGN) { if ((r = redir_varassign (redirect, redirector)) < 0) @@ -1148,10 +1133,8 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp) else if (dup2 (redir_fd, redirector) < 0) return (errno); -#if defined (BUFFERED_INPUT) if (ri == r_duplicating_input || ri == r_move_input) duplicate_buffered_stream (redir_fd, redirector); -#endif /* BUFFERED_INPUT */ /* First duplicate the close-on-exec state of redirectee. dup2 leaves the flag unset on the new descriptor, which means it @@ -1218,14 +1201,10 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp) #endif xtrace_fdchk (redirector); -#if defined (BUFFERED_INPUT) /* inhibit call to sync_buffered_stream() for async processes */ if (redirector != 0 || (subshell_environment & SUBSHELL_ASYNC) == 0) check_bash_input (redirector); r = close_buffered_fd (redirector); -#else /* !BUFFERED_INPUT */ - r = close (redirector); -#endif /* !BUFFERED_INPUT */ if (r < 0 && (flags & RX_INTERNAL) && (errno == EIO || errno == ENOSPC)) REDIRECTION_ERROR (r, errno, -1); diff --git a/shell.c b/shell.c index a64e8e003..28940ad13 100644 --- a/shell.c +++ b/shell.c @@ -1,6 +1,6 @@ /* shell.c -- GNU's idea of the POSIX shell specification. */ -/* 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. @@ -288,10 +288,8 @@ char **subshell_envp; char *exec_argv0; -#if defined (BUFFERED_INPUT) /* The file descriptor from which the shell is reading input. */ int default_buffered_input = -1; -#endif /* The following two variables are not static so they can show up in $-. */ int read_from_stdin; /* -s flag supplied */ @@ -438,9 +436,7 @@ main (int argc, char **argv, char **env) command_execution_string = shell_script_filename = NULL; want_pending_command = locally_skip_execution = read_from_stdin = 0; default_input = stdin; -#if defined (BUFFERED_INPUT) default_buffered_input = -1; -#endif /* Fix for the `infinite process creation' bug when running shell scripts from startup files on System V. */ @@ -772,11 +768,7 @@ main (int argc, char **argv, char **env) { /* In this mode, bash is reading a script from stdin, which is a pipe or redirected file. */ -#if defined (BUFFERED_INPUT) default_buffered_input = fileno (stdin); /* == 0 */ -#else - setbuf (default_input, NULL); -#endif /* !BUFFERED_INPUT */ read_from_stdin = 1; } else if (top_level_arg_index == argc) /* arg index before startup files */ @@ -1672,22 +1664,8 @@ open_shell_script (char *script_name) not match with ours. */ fd = move_to_high_fd (fd, 1, -1); -#if defined (BUFFERED_INPUT) default_buffered_input = fd; SET_CLOSE_ON_EXEC (default_buffered_input); -#else /* !BUFFERED_INPUT */ - default_input = fdopen (fd, "r"); - - if (default_input == 0) - { - file_error (filename); - exit (EX_NOTFOUND); - } - - SET_CLOSE_ON_EXEC (fd); - if (fileno (default_input) != fd) - SET_CLOSE_ON_EXEC (fileno (default_input)); -#endif /* !BUFFERED_INPUT */ /* Just about the only way for this code to be executed is if something like `bash -i /dev/stdin' is executed. */ @@ -1696,12 +1674,7 @@ open_shell_script (char *script_name) dup2 (fd, 0); close (fd); fd = 0; -#if defined (BUFFERED_INPUT) default_buffered_input = 0; -#else - fclose (default_input); - default_input = stdin; -#endif } else if (forced_interactive && fd_is_tty == 0) /* But if a script is called with something like `bash -i scriptname', @@ -1721,20 +1694,16 @@ set_bash_input (void) { /* Make sure the fd from which we are reading input is not in no-delay mode. */ -#if defined (BUFFERED_INPUT) if (interactive == 0) sh_unset_nodelay_mode (default_buffered_input); else -#endif /* !BUFFERED_INPUT */ sh_unset_nodelay_mode (fileno (stdin)); /* with_input_from_stdin really means `with_input_from_readline' */ if (interactive && no_line_editing == 0) with_input_from_stdin (); -#if defined (BUFFERED_INPUT) else if (interactive == 0) with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]); -#endif /* BUFFERED_INPUT */ else with_input_from_stream (default_input, dollar_vars[0]); } @@ -1746,7 +1715,6 @@ set_bash_input (void) void unset_bash_input (int check_zero) { -#if defined (BUFFERED_INPUT) if ((check_zero && default_buffered_input >= 0) || (check_zero == 0 && default_buffered_input > 0)) { @@ -1754,13 +1722,6 @@ unset_bash_input (int check_zero) default_buffered_input = bash_input.location.buffered_fd = -1; bash_input.type = st_none; /* XXX */ } -#else /* !BUFFERED_INPUT */ - if (default_input) - { - fclose (default_input); - default_input = (FILE *)NULL; - } -#endif /* !BUFFERED_INPUT */ } diff --git a/tests/varenv.right b/tests/varenv.right index f6bd1b5bd..48b0abd28 100644 --- a/tests/varenv.right +++ b/tests/varenv.right @@ -272,6 +272,32 @@ trap -- 'echo trap:$FUNCNAME' EXIT trap:f trap -- 'echo trap:$FUNCNAME' EXIT trap:f +declare -rx x="4" +declare -rx y="5" +f:3 +f1:3 +global1:bcde +f:3 +f1:3 +global2:bcde +f:3 +f1:3 +global:bcde +f:3 +f1:3 +global:bcde +f:3 +bcde +f:3 +bcde +f1:3 +global: bcde +f1:3 +global: 3 +f: 3 +global: declare -rx c="3" +f1: 4 +global: declare -- b="8" a=z a=b a=z diff --git a/tests/varenv.tests b/tests/varenv.tests index 68c619ec7..9a111c1f9 100644 --- a/tests/varenv.tests +++ b/tests/varenv.tests @@ -260,6 +260,7 @@ ${THIS_SH} ./varenv19.sub ${THIS_SH} ./varenv20.sub ${THIS_SH} ./varenv21.sub ${THIS_SH} ./varenv22.sub +${THIS_SH} ./varenv23.sub # make sure variable scoping is done right tt() { typeset a=b;echo a=$a; };a=z;echo a=$a;tt;echo a=$a diff --git a/tests/varenv23.sub b/tests/varenv23.sub new file mode 100644 index 000000000..03202ad4a --- /dev/null +++ b/tests/varenv23.sub @@ -0,0 +1,95 @@ +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# posix rules for assignments preceding export/readonly in functions, using +# local and global vars; default rules for assignments preceding declare/local +# in functions, always using local vars. +# +# changes to local variables should never propagate upward from the function +# to its caller, even in posix mode + +x=1 +x=4 declare -r x +declare -p x +y=2 +y=5 readonly y +declare -p y +# can't use x and y from here on + +f() { local -r a=3; echo f:$a; } +f1() { declare -r b=3; echo f1:$b; } + +a=4 f +b=4 f1 +echo global1:$a $b + +set -o posix +a=4 f +b=4 f1 +echo global2:$a $b +set +o posix + +unset -f f f1 + +f() { local a=3; readonly a; echo f:$a; } +f1() { local b=3; declare -r b; echo f1:$b; } + +a=4 f +b=4 f1 +echo global:$a $b + +set -o posix +a=4 f +b=4 f1 +echo global:$a $b +set +o posix + +unset -f f f1 + +f() { local a; a=3 readonly a; echo f:$a; } + +a=4 f +echo $a +set -o posix +a=4 f +echo $a +set +o posix + +f1() { a=3 readonly a; echo f1:$a; } + +a=7 f1 +echo global: $a + +set -o posix +a=7 f1 +echo global: $a +set +o posix + +unset -f f f1 +# can't use a from here on + +c=7 b=8 +f() { c=3 readonly c; echo f: $c; } +f1() { b=4 declare -r b; echo f1: $b; } + +f +echo global: $(declare -p c) + +f1 +echo global: $(declare -p b) + +unset -f f f1 + +# can't use c from here on + + diff --git a/variables.c b/variables.c index a643185dc..9f9440673 100644 --- a/variables.c +++ b/variables.c @@ -4504,7 +4504,7 @@ propagate_temp_var (PTR_T data) SHELL_VAR *var; var = (SHELL_VAR *)data; - if (tempvar_p (var) && (var->attributes & att_propagate)) + if (tempvar_p (var) && propagate_p (var)) push_temp_var (data); else { @@ -5307,7 +5307,7 @@ push_exported_var (PTR_T data) propagated, bind it in the previous scope before disposing it. */ /* XXX - This isn't exactly right, because all tempenv variables have the export attribute set. */ - if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate)) + if (tempvar_p (var) && exported_p (var) && propagate_p (var)) { var->attributes &= ~att_tempvar; /* XXX */ v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);