|
1 BASH PATCH REPORT |
|
2 ================= |
|
3 |
|
4 Bash-Release: 4.3 |
|
5 Patch-ID: bash43-033 |
|
6 |
|
7 Bug-Reported-by: [email protected], Jan Rome <[email protected]> |
|
8 Bug-Reference-ID: <[email protected]>, |
|
9 <[email protected]> |
|
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 *** ../bash-4.3-patched/shell.c 2014-01-14 08:04:32.000000000 -0500 |
|
24 --- shell.c 2014-12-22 10:27:50.000000000 -0500 |
|
25 *************** |
|
26 *** 74,77 **** |
|
27 --- 74,78 ---- |
|
28 |
|
29 #if defined (READLINE) |
|
30 + # include <readline/readline.h> |
|
31 # include "bashline.h" |
|
32 #endif |
|
33 *************** |
|
34 *** 910,913 **** |
|
35 --- 912,923 ---- |
|
36 fflush (stderr); |
|
37 |
|
38 + /* Clean up the terminal if we are in a state where it's been modified. */ |
|
39 + #if defined (READLINE) |
|
40 + if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function) |
|
41 + (*rl_deprep_term_function) (); |
|
42 + #endif |
|
43 + if (read_tty_modified ()) |
|
44 + read_tty_cleanup (); |
|
45 + |
|
46 /* Do trap[0] if defined. Allow it to override the exit status |
|
47 passed to us. */ |
|
48 *** ../bash-4.3-patched/builtins/read.def 2014-10-01 12:57:38.000000000 -0400 |
|
49 --- builtins/read.def 2014-12-22 10:48:54.000000000 -0500 |
|
50 *************** |
|
51 *** 141,148 **** |
|
52 int sigalrm_seen; |
|
53 |
|
54 ! static int reading; |
|
55 static SigHandler *old_alrm; |
|
56 static unsigned char delim; |
|
57 |
|
58 /* In all cases, SIGALRM just sets a flag that we check periodically. This |
|
59 avoids problems with the semi-tricky stuff we do with the xfree of |
|
60 --- 141,150 ---- |
|
61 int sigalrm_seen; |
|
62 |
|
63 ! static int reading, tty_modified; |
|
64 static SigHandler *old_alrm; |
|
65 static unsigned char delim; |
|
66 |
|
67 + static struct ttsave termsave; |
|
68 + |
|
69 /* In all cases, SIGALRM just sets a flag that we check periodically. This |
|
70 avoids problems with the semi-tricky stuff we do with the xfree of |
|
71 *************** |
|
72 *** 189,193 **** |
|
73 SHELL_VAR *var; |
|
74 TTYSTRUCT ttattrs, ttset; |
|
75 - struct ttsave termsave; |
|
76 #if defined (ARRAY_VARS) |
|
77 WORD_LIST *alist; |
|
78 --- 191,194 ---- |
|
79 *************** |
|
80 *** 222,226 **** |
|
81 USE_VAR(lastsig); |
|
82 |
|
83 ! sigalrm_seen = reading = 0; |
|
84 |
|
85 i = 0; /* Index into the string that we are reading. */ |
|
86 --- 223,227 ---- |
|
87 USE_VAR(lastsig); |
|
88 |
|
89 ! sigalrm_seen = reading = tty_modified = 0; |
|
90 |
|
91 i = 0; /* Index into the string that we are reading. */ |
|
92 *************** |
|
93 *** 439,442 **** |
|
94 --- 440,445 ---- |
|
95 goto assign_vars; |
|
96 } |
|
97 + if (interactive_shell == 0) |
|
98 + initialize_terminating_signals (); |
|
99 old_alrm = set_signal_handler (SIGALRM, sigalrm); |
|
100 add_unwind_protect (reset_alarm, (char *)NULL); |
|
101 *************** |
|
102 *** 483,487 **** |
|
103 --- 486,493 ---- |
|
104 if (i < 0) |
|
105 sh_ttyerror (1); |
|
106 + tty_modified = 1; |
|
107 add_unwind_protect ((Function *)ttyrestore, (char *)&termsave); |
|
108 + if (interactive_shell == 0) |
|
109 + initialize_terminating_signals (); |
|
110 } |
|
111 } |
|
112 *************** |
|
113 *** 498,502 **** |
|
114 --- 504,511 ---- |
|
115 sh_ttyerror (1); |
|
116 |
|
117 + tty_modified = 1; |
|
118 add_unwind_protect ((Function *)ttyrestore, (char *)&termsave); |
|
119 + if (interactive_shell == 0) |
|
120 + initialize_terminating_signals (); |
|
121 } |
|
122 |
|
123 *************** |
|
124 *** 589,592 **** |
|
125 --- 598,603 ---- |
|
126 else |
|
127 lastsig = 0; |
|
128 + if (terminating_signal && tty_modified) |
|
129 + ttyrestore (&termsave); /* fix terminal before exiting */ |
|
130 CHECK_TERMSIG; |
|
131 eof = 1; |
|
132 *************** |
|
133 *** 979,982 **** |
|
134 --- 990,1007 ---- |
|
135 { |
|
136 ttsetattr (ttp->fd, ttp->attrs); |
|
137 + tty_modified = 0; |
|
138 + } |
|
139 + |
|
140 + void |
|
141 + read_tty_cleanup () |
|
142 + { |
|
143 + if (tty_modified) |
|
144 + ttyrestore (&termsave); |
|
145 + } |
|
146 + |
|
147 + int |
|
148 + read_tty_modified () |
|
149 + { |
|
150 + return (tty_modified); |
|
151 } |
|
152 |
|
153 *** ../bash-4.3-patched/builtins/common.h 2014-10-01 12:57:47.000000000 -0400 |
|
154 --- builtins/common.h 2014-12-22 10:10:14.000000000 -0500 |
|
155 *************** |
|
156 *** 123,126 **** |
|
157 --- 141,148 ---- |
|
158 extern void getopts_reset __P((int)); |
|
159 |
|
160 + /* Functions from read.def */ |
|
161 + extern void read_tty_cleanup __P((void)); |
|
162 + extern int read_tty_modified __P((void)); |
|
163 + |
|
164 /* Functions from set.def */ |
|
165 extern int minus_o_option_value __P((char *)); |
|
166 *** ../bash-4.3-patched/bashline.c 2014-05-14 09:22:39.000000000 -0400 |
|
167 --- bashline.c 2014-09-08 11:28:56.000000000 -0400 |
|
168 *************** |
|
169 *** 203,206 **** |
|
170 --- 203,207 ---- |
|
171 extern int array_needs_making; |
|
172 extern int posixly_correct, no_symbolic_links; |
|
173 + extern int sigalrm_seen; |
|
174 extern char *current_prompt_string, *ps1_prompt; |
|
175 extern STRING_INT_ALIST word_token_alist[]; |
|
176 *************** |
|
177 *** 4209,4214 **** |
|
178 /* If we're going to longjmp to top_level, make sure we clean up readline. |
|
179 check_signals will call QUIT, which will eventually longjmp to top_level, |
|
180 ! calling run_interrupt_trap along the way. */ |
|
181 ! if (interrupt_state) |
|
182 rl_cleanup_after_signal (); |
|
183 bashline_reset_event_hook (); |
|
184 --- 4262,4268 ---- |
|
185 /* If we're going to longjmp to top_level, make sure we clean up readline. |
|
186 check_signals will call QUIT, which will eventually longjmp to top_level, |
|
187 ! calling run_interrupt_trap along the way. The check for sigalrm_seen is |
|
188 ! to clean up the read builtin's state. */ |
|
189 ! if (terminating_signal || interrupt_state || sigalrm_seen) |
|
190 rl_cleanup_after_signal (); |
|
191 bashline_reset_event_hook (); |
|
192 *** ../bash-4.3-patched/sig.c 2014-01-10 15:06:06.000000000 -0500 |
|
193 --- sig.c 2014-09-08 11:26:33.000000000 -0400 |
|
194 *************** |
|
195 *** 533,538 **** |
|
196 /* Set the event hook so readline will call it after the signal handlers |
|
197 finish executing, so if this interrupted character input we can get |
|
198 ! quick response. */ |
|
199 ! if (interactive_shell && interactive && no_line_editing == 0) |
|
200 bashline_set_event_hook (); |
|
201 #endif |
|
202 --- 533,540 ---- |
|
203 /* Set the event hook so readline will call it after the signal handlers |
|
204 finish executing, so if this interrupted character input we can get |
|
205 ! quick response. If readline is active or has modified the terminal we |
|
206 ! need to set this no matter what the signal is, though the check for |
|
207 ! RL_STATE_TERMPREPPED is possibly redundant. */ |
|
208 ! if (RL_ISSTATE (RL_STATE_SIGHANDLER) || RL_ISSTATE (RL_STATE_TERMPREPPED)) |
|
209 bashline_set_event_hook (); |
|
210 #endif |
|
211 *** ../bash-4.3/patchlevel.h 2012-12-29 10:47:57.000000000 -0500 |
|
212 --- patchlevel.h 2014-03-20 20:01:28.000000000 -0400 |
|
213 *************** |
|
214 *** 26,30 **** |
|
215 looks for to find the patch level (for the sccs version string). */ |
|
216 |
|
217 ! #define PATCHLEVEL 32 |
|
218 |
|
219 #endif /* _PATCHLEVEL_H_ */ |
|
220 --- 26,30 ---- |
|
221 looks for to find the patch level (for the sccs version string). */ |
|
222 |
|
223 ! #define PATCHLEVEL 33 |
|
224 |
|
225 #endif /* _PATCHLEVEL_H_ */ |