From: Sertonix <[email protected]>

In fd47f056765 (lineedit: print prompt and editing operations to stderr)
some output was left printing to stdout. This causes a race condition
between stderr and stdout which in some cases leads to output written in
the wrong places.

Downstream issue: https://gitlab.alpinelinux.org/alpine/aports/-/issues/16566
Fixes: fd47f056765

function                                             old     new   delta
fputs_stderr                                           -      12     +12
put_cur_glyph_and_inc_cursor                         182     178      -4
put_prompt_custom                                     52      45      -7
input_delete                                         161     154      -7
draw_custom                                           84      77      -7
BB_PUTCHAR                                           164     157      -7
read_line_input                                     3612    3579     -33
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/6 up/down: 12/-65)            Total: -53 bytes
   text    data     bss     dec     hex filename
 824213   14108    2008  840329   cd289 busybox_old
 824160   14108    2008  840276   cd254 busybox_unstripped

Signed-off-by: Sertonix <[email protected]>
Signed-off-by: Natanael Copa <[email protected]>
---

v2 -> v3:
Introduce a fputs_stderr() func to reduce size.

Denys, It would be nice if this could be applied and backported to
1_37_stable.

Thanks!


 libbb/lineedit.c | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 151208c1c..21fd6037c 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -345,6 +345,12 @@ static unsigned save_string(char *dst, unsigned maxsize)
                return i;
        }
 }
+
+static void fputs_stderr(const char *buf)
+{
+       fputs(buf, stderr);
+}
+
 /* I thought just fputwc(c, stderr) would work. But no... */
 static void BB_PUTCHAR(wchar_t c)
 {
@@ -354,7 +360,7 @@ static void BB_PUTCHAR(wchar_t c)
                ssize_t len = wcrtomb(buf, c, &mbst);
                if (len > 0) {
                        buf[len] = '\0';
-                       fputs(buf, stderr);
+                       fputs_stderr(buf);
                }
        } else {
                /* In this case, c is always one byte */
@@ -451,7 +457,7 @@ static void put_cur_glyph_and_inc_cursor(void)
                 * have automargin (IOW: it is moving cursor to next line
                 * by itself (which is wrong for VT-10x terminals)),
                 * this will break things: there will be one extra empty line */
-               puts("\r"); /* + implicit '\n' */
+               bb_putchar_stderr('\r'); /* + implicit '\n' */
 #else
                /* VT-10x terminals don't wrap cursor to next line when last 
char
                 * on the line is printed - cursor stays "over" this char.
@@ -505,7 +511,7 @@ static void put_prompt_custom(bool is_full)
        /* 
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
         * says that shells must write $PSn to stderr, not stdout.
         */
-       fputs((is_full ? cmdedit_prompt : prompt_last_line), stderr);
+       fputs_stderr((is_full ? cmdedit_prompt : prompt_last_line));
        cursor = 0;
        cmdedit_y = cmdedit_prmt_len / cmdedit_termw; /* new quasireal y */
        cmdedit_x = cmdedit_prmt_len % cmdedit_termw;
@@ -607,7 +613,7 @@ static void draw_custom(int y, int back_cursor, bool 
is_full)
        bb_putchar_stderr('\r');
        put_prompt_custom(is_full);
        put_till_end_and_adv_cursor();
-       fputs(SEQ_CLEAR_TILL_END_OF_SCREEN, stderr);
+       fputs_stderr(SEQ_CLEAR_TILL_END_OF_SCREEN);
        input_backward(back_cursor);
 }
 
@@ -652,7 +658,7 @@ static void input_delete(int save)
        command_len--;
        put_till_end_and_adv_cursor();
        /* Last char is still visible, erase it (and more) */
-       fputs(SEQ_CLEAR_TILL_END_OF_SCREEN, stderr);
+       fputs_stderr(SEQ_CLEAR_TILL_END_OF_SCREEN);
        input_backward(cursor - j);     /* back to old pos cursor */
 }
 
@@ -1170,9 +1176,9 @@ static void showfiles(void)
                        );
                }
                if (ENABLE_UNICODE_SUPPORT)
-                       puts(printable_string(matches[n]));
+                       fputs_stderr(printable_string(matches[n]));
                else
-                       puts(matches[n]);
+                       fputs_stderr(matches[n]);
        }
 }
 
@@ -1903,7 +1909,7 @@ static void ask_terminal(void)
        pfd.events = POLLIN;
        if (safe_poll(&pfd, 1, 0) == 0) {
                S.sent_ESC_br6n = 1;
-               fputs(ESC"[6n", stderr);
+               fputs_stderr(ESC"[6n");
                fflush_all(); /* make terminal see it ASAP! */
        }
 }
@@ -2642,13 +2648,13 @@ int FAST_FUNC read_line_input(line_input_t *st, const 
char *prompt, char *comman
                        /* Control-k -- clear to end of line */
                        command_ps[cursor] = BB_NUL;
                        command_len = cursor;
-                       fputs(SEQ_CLEAR_TILL_END_OF_SCREEN, stderr);
+                       fputs_stderr(SEQ_CLEAR_TILL_END_OF_SCREEN);
                        break;
                case CTRL('L'):
                vi_case(CTRL('L')|VI_CMDMODE_BIT:)
                        /* Control-l -- clear screen */
                        /* cursor to top,left; clear to the end of screen */
-                       fputs(ESC"[H" ESC"[J", stderr);
+                       fputs_stderr(ESC"[H" ESC"[J");
                        draw_full(command_len - cursor);
                        break;
 #if MAX_HISTORY > 0
@@ -3033,7 +3039,7 @@ int FAST_FUNC read_line_input(const char* prompt, char* 
command, int maxsize)
        /* 
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
         * says that shells must write $PSn to stderr, not stdout.
         */
-       fputs(prompt, stderr);
+       fputs_stderr(prompt);
        fflush_all();
        if (!fgets(command, maxsize, stdin))
                return -1;
-- 
2.47.1

_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox

Reply via email to