← Commit list

93e0898c6

Denys Vlasenko
Denys Vlasenko
2023-01-26
SUCCESS Duration: 163s

Subject

shell: fix SIGWINCH and SIGCHLD (in hush) interrupting line input, closes 15256

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

libbb/lineedit.c+10 -7
@@ -2180,7 +2180,8 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
* "\xff\n",pause,"ls\n" invalid and thus won't lose "ls".
*
* If LI_INTERRUPTIBLE, return -1 if got EINTR in poll()
- * inside read_key, or if bb_got_signal != 0 (IOW: if signal
+ * inside read_key and bb_got_signal became != 0,
+ * or if bb_got_signal != 0 (IOW: if signal
* arrived before poll() is reached).
*
* Note: read_key sets errno to 0 on success.
@@ -2197,14 +2198,16 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 0;)
if (errno != EINTR)
break;
+ /* It was EINTR. Repeat read_key() unless... */
if (state->flags & LI_INTERRUPTIBLE) {
- /* LI_INTERRUPTIBLE bails out on EINTR,
- * but nothing really guarantees that bb_got_signal
- * is nonzero. Follow the least surprise principle:
+ /* LI_INTERRUPTIBLE bails out on EINTR
+ * if bb_got_signal became nonzero.
+ * (It may stay zero: for example, our SIGWINCH
+ * handler does not set it. This is used for signals
+ * which should not interrupt line editing).
*/
- if (bb_got_signal == 0)
- bb_got_signal = 255;
- goto ret;
+ if (bb_got_signal != 0)
+ goto ret; /* will return -1 */
}
}
shell/ash.c+2 -1
@@ -10821,7 +10821,8 @@ preadfd(void)
again:
/* For shell, LI_INTERRUPTIBLE is set:
* read_line_input will abort on either
- * getting EINTR in poll(), or if it sees bb_got_signal != 0
+ * getting EINTR in poll() and bb_got_signal became != 0,
+ * or if it sees bb_got_signal != 0
* (IOW: if signal arrives before poll() is reached).
* Interactive testcases:
* (while kill -INT $$; do sleep 1; done) &
shell/hush.c+8 -2
@@ -1946,7 +1946,12 @@ static void record_pending_signo(int sig)
{
sigaddset(&G.pending_set, sig);
#if ENABLE_FEATURE_EDITING
- bb_got_signal = sig; /* for read_line_input: "we got a signal" */
+ if (sig != SIGCHLD
+ || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0])
+ /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */
+ ) {
+ bb_got_signal = sig; /* for read_line_input: "we got a signal" */
+ }
#endif
#if ENABLE_HUSH_FAST
if (sig == SIGCHLD) {
@@ -2669,7 +2674,8 @@ static int get_user_input(struct in_str *i)
} else {
/* For shell, LI_INTERRUPTIBLE is set:
* read_line_input will abort on either
- * getting EINTR in poll(), or if it sees bb_got_signal != 0
+ * getting EINTR in poll() and bb_got_signal became != 0,
+ * or if it sees bb_got_signal != 0
* (IOW: if signal arrives before poll() is reached).
* Interactive testcases:
* (while kill -INT $$; do sleep 1; done) &