|
@@ -0,0 +1,201 @@
|
|
1
|
+ BASH PATCH REPORT
|
|
2
|
+ =================
|
|
3
|
+
|
|
4
|
+Bash-Release: 4.3
|
|
5
|
+Patch-ID: bash43-033
|
|
6
|
+
|
|
7
|
+Bug-Reported-by: mickael9@gmail.com, Jan Rome <jan.rome@gmail.com>
|
|
8
|
+Bug-Reference-ID: <20140907224046.382ED3610CC@mickael-laptop.localdomain>,
|
|
9
|
+ <540D661D.50908@gmail.com>
|
|
10
|
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2014-09/msg00029.html
|
|
11
|
+ http://lists.gnu.org/archive/html/bug-bash/2014-09/msg00030.html
|
|
12
|
+
|
|
13
|
+Bug-Description:
|
|
14
|
+
|
|
15
|
+Bash does not clean up the terminal state in all cases where bash or
|
|
16
|
+readline modifies it and bash is subsequently terminated by a fatal signal.
|
|
17
|
+This happens when the `read' builtin modifies the terminal settings, both
|
|
18
|
+when readline is active and when it is not. It occurs most often when a script
|
|
19
|
+installs a trap that exits on a signal without re-sending the signal to itself.
|
|
20
|
+
|
|
21
|
+Patch (apply with `patch -p0'):
|
|
22
|
+
|
|
23
|
+--- a/shell.c
|
|
24
|
++++ b/shell.c
|
|
25
|
+@@ -73,6 +73,7 @@
|
|
26
|
+ #endif
|
|
27
|
+
|
|
28
|
+ #if defined (READLINE)
|
|
29
|
++# include <readline/readline.h>
|
|
30
|
+ # include "bashline.h"
|
|
31
|
+ #endif
|
|
32
|
+
|
|
33
|
+@@ -909,6 +910,14 @@ exit_shell (s)
|
|
34
|
+ fflush (stdout); /* XXX */
|
|
35
|
+ fflush (stderr);
|
|
36
|
+
|
|
37
|
++ /* Clean up the terminal if we are in a state where it's been modified. */
|
|
38
|
++#if defined (READLINE)
|
|
39
|
++ if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function)
|
|
40
|
++ (*rl_deprep_term_function) ();
|
|
41
|
++#endif
|
|
42
|
++ if (read_tty_modified ())
|
|
43
|
++ read_tty_cleanup ();
|
|
44
|
++
|
|
45
|
+ /* Do trap[0] if defined. Allow it to override the exit status
|
|
46
|
+ passed to us. */
|
|
47
|
+ if (signal_is_trapped (0))
|
|
48
|
+--- a/builtins/read.def
|
|
49
|
++++ b/builtins/read.def
|
|
50
|
+@@ -140,10 +140,12 @@ static void reset_alarm __P((void));
|
|
51
|
+ procenv_t alrmbuf;
|
|
52
|
+ int sigalrm_seen;
|
|
53
|
+
|
|
54
|
+-static int reading;
|
|
55
|
++static int reading, tty_modified;
|
|
56
|
+ static SigHandler *old_alrm;
|
|
57
|
+ static unsigned char delim;
|
|
58
|
+
|
|
59
|
++static struct ttsave termsave;
|
|
60
|
++
|
|
61
|
+ /* In all cases, SIGALRM just sets a flag that we check periodically. This
|
|
62
|
+ avoids problems with the semi-tricky stuff we do with the xfree of
|
|
63
|
+ input_string at the top of the unwind-protect list (see below). */
|
|
64
|
+@@ -188,7 +190,6 @@ read_builtin (list)
|
|
65
|
+ struct stat tsb;
|
|
66
|
+ SHELL_VAR *var;
|
|
67
|
+ TTYSTRUCT ttattrs, ttset;
|
|
68
|
+- struct ttsave termsave;
|
|
69
|
+ #if defined (ARRAY_VARS)
|
|
70
|
+ WORD_LIST *alist;
|
|
71
|
+ #endif
|
|
72
|
+@@ -221,7 +222,7 @@ read_builtin (list)
|
|
73
|
+ USE_VAR(ps2);
|
|
74
|
+ USE_VAR(lastsig);
|
|
75
|
+
|
|
76
|
+- sigalrm_seen = reading = 0;
|
|
77
|
++ sigalrm_seen = reading = tty_modified = 0;
|
|
78
|
+
|
|
79
|
+ i = 0; /* Index into the string that we are reading. */
|
|
80
|
+ raw = edit = 0; /* Not reading raw input by default. */
|
|
81
|
+@@ -438,6 +439,8 @@ read_builtin (list)
|
|
82
|
+ retval = 128+SIGALRM;
|
|
83
|
+ goto assign_vars;
|
|
84
|
+ }
|
|
85
|
++ if (interactive_shell == 0)
|
|
86
|
++ initialize_terminating_signals ();
|
|
87
|
+ old_alrm = set_signal_handler (SIGALRM, sigalrm);
|
|
88
|
+ add_unwind_protect (reset_alarm, (char *)NULL);
|
|
89
|
+ #if defined (READLINE)
|
|
90
|
+@@ -482,7 +485,10 @@ read_builtin (list)
|
|
91
|
+ i = silent ? ttfd_cbreak (fd, &ttset) : ttfd_onechar (fd, &ttset);
|
|
92
|
+ if (i < 0)
|
|
93
|
+ sh_ttyerror (1);
|
|
94
|
++ tty_modified = 1;
|
|
95
|
+ add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
|
|
96
|
++ if (interactive_shell == 0)
|
|
97
|
++ initialize_terminating_signals ();
|
|
98
|
+ }
|
|
99
|
+ }
|
|
100
|
+ else if (silent) /* turn off echo but leave term in canonical mode */
|
|
101
|
+@@ -497,7 +503,10 @@ read_builtin (list)
|
|
102
|
+ if (i < 0)
|
|
103
|
+ sh_ttyerror (1);
|
|
104
|
+
|
|
105
|
++ tty_modified = 1;
|
|
106
|
+ add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
|
|
107
|
++ if (interactive_shell == 0)
|
|
108
|
++ initialize_terminating_signals ();
|
|
109
|
+ }
|
|
110
|
+
|
|
111
|
+ /* This *must* be the top unwind-protect on the stack, so the manipulation
|
|
112
|
+@@ -588,6 +597,8 @@ read_builtin (list)
|
|
113
|
+ }
|
|
114
|
+ else
|
|
115
|
+ lastsig = 0;
|
|
116
|
++ if (terminating_signal && tty_modified)
|
|
117
|
++ ttyrestore (&termsave); /* fix terminal before exiting */
|
|
118
|
+ CHECK_TERMSIG;
|
|
119
|
+ eof = 1;
|
|
120
|
+ break;
|
|
121
|
+@@ -978,6 +989,20 @@ ttyrestore (ttp)
|
|
122
|
+ struct ttsave *ttp;
|
|
123
|
+ {
|
|
124
|
+ ttsetattr (ttp->fd, ttp->attrs);
|
|
125
|
++ tty_modified = 0;
|
|
126
|
++}
|
|
127
|
++
|
|
128
|
++void
|
|
129
|
++read_tty_cleanup ()
|
|
130
|
++{
|
|
131
|
++ if (tty_modified)
|
|
132
|
++ ttyrestore (&termsave);
|
|
133
|
++}
|
|
134
|
++
|
|
135
|
++int
|
|
136
|
++read_tty_modified ()
|
|
137
|
++{
|
|
138
|
++ return (tty_modified);
|
|
139
|
+ }
|
|
140
|
+
|
|
141
|
+ #if defined (READLINE)
|
|
142
|
+--- a/builtins/common.h
|
|
143
|
++++ b/builtins/common.h
|
|
144
|
+@@ -122,6 +122,10 @@ extern void bash_logout __P((void));
|
|
145
|
+ /* Functions from getopts.def */
|
|
146
|
+ extern void getopts_reset __P((int));
|
|
147
|
+
|
|
148
|
++/* Functions from read.def */
|
|
149
|
++extern void read_tty_cleanup __P((void));
|
|
150
|
++extern int read_tty_modified __P((void));
|
|
151
|
++
|
|
152
|
+ /* Functions from set.def */
|
|
153
|
+ extern int minus_o_option_value __P((char *));
|
|
154
|
+ extern void list_minus_o_opts __P((int, int));
|
|
155
|
+--- a/bashline.c
|
|
156
|
++++ b/bashline.c
|
|
157
|
+@@ -202,6 +202,7 @@ extern int current_command_line_count, s
|
|
158
|
+ extern int last_command_exit_value;
|
|
159
|
+ extern int array_needs_making;
|
|
160
|
+ extern int posixly_correct, no_symbolic_links;
|
|
161
|
++extern int sigalrm_seen;
|
|
162
|
+ extern char *current_prompt_string, *ps1_prompt;
|
|
163
|
+ extern STRING_INT_ALIST word_token_alist[];
|
|
164
|
+ extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
|
|
165
|
+@@ -4208,8 +4209,9 @@ bash_event_hook ()
|
|
166
|
+ {
|
|
167
|
+ /* If we're going to longjmp to top_level, make sure we clean up readline.
|
|
168
|
+ check_signals will call QUIT, which will eventually longjmp to top_level,
|
|
169
|
+- calling run_interrupt_trap along the way. */
|
|
170
|
+- if (interrupt_state)
|
|
171
|
++ calling run_interrupt_trap along the way. The check for sigalrm_seen is
|
|
172
|
++ to clean up the read builtin's state. */
|
|
173
|
++ if (terminating_signal || interrupt_state || sigalrm_seen)
|
|
174
|
+ rl_cleanup_after_signal ();
|
|
175
|
+ bashline_reset_event_hook ();
|
|
176
|
+ check_signals_and_traps (); /* XXX */
|
|
177
|
+--- a/sig.c
|
|
178
|
++++ b/sig.c
|
|
179
|
+@@ -532,8 +532,10 @@ termsig_sighandler (sig)
|
|
180
|
+ #if defined (READLINE)
|
|
181
|
+ /* Set the event hook so readline will call it after the signal handlers
|
|
182
|
+ finish executing, so if this interrupted character input we can get
|
|
183
|
+- quick response. */
|
|
184
|
+- if (interactive_shell && interactive && no_line_editing == 0)
|
|
185
|
++ quick response. If readline is active or has modified the terminal we
|
|
186
|
++ need to set this no matter what the signal is, though the check for
|
|
187
|
++ RL_STATE_TERMPREPPED is possibly redundant. */
|
|
188
|
++ if (RL_ISSTATE (RL_STATE_SIGHANDLER) || RL_ISSTATE (RL_STATE_TERMPREPPED))
|
|
189
|
+ bashline_set_event_hook ();
|
|
190
|
+ #endif
|
|
191
|
+
|
|
192
|
+--- a/patchlevel.h
|
|
193
|
++++ b/patchlevel.h
|
|
194
|
+@@ -25,6 +25,6 @@
|
|
195
|
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
|
|
196
|
+ looks for to find the patch level (for the sccs version string). */
|
|
197
|
+
|
|
198
|
+-#define PATCHLEVEL 32
|
|
199
|
++#define PATCHLEVEL 33
|
|
200
|
+
|
|
201
|
+ #endif /* _PATCHLEVEL_H_ */
|