From 0647e53bd15c8982d89a03c2db1643aedd7cd649 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Tue, 10 Jan 2023 10:23:14 -0500 Subject: [PATCH] fix for completing quoted filenames with show-all-if-ambiguous set; avoid signed int overflow in intrand32 --- CWRU/CWRU.chlog | 27 +++++++++++++++++++++++++++ doc/bash.1 | 2 +- doc/bashref.texi | 6 +++--- input.c | 7 +++++++ input.h | 16 +++++++--------- lib/readline/complete.c | 18 +++++++++++++++++- lib/sh/random.c | 4 ++-- parse.y | 21 +++++++++++++++++++-- 8 files changed, 83 insertions(+), 18 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 6a074194..575c9cec 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -4978,3 +4978,30 @@ lib/readline/{vi_mode.c,histfile.c,funmap.c,complete.c,display.c,bind.c,isearch. lib/tilde/tilde.c - final code cleanups for ANSI C and lint/ubsan/asan runs + 1/7 + --- +lib/readline/complete.c + - rl_complete_internal: when computing nontrivial_lcd and the length + of the text from the line buffer, dequote the text from the line + buffer before comparing it against the common prefix of the matches + (matches[0]), so we don't get spurious mismatches if the quoted text + from the line is longer than the unquoted match. Report from + Martin Castillo + +input.[ch] + - get_buffered_stream(fd): new function, return the BUFFERED_STREAM * + corresponding to file descriptor FD, if it exists + + 1/8 + --- +parse.y + - shell_getc: if yy_getc returns EOF but the buffered stream input + indicates an error state, set shell_input_line_terminator to + READERR. Currently treated the same as EOF. + + 1/10 + ---- +lib/sh/random.c + - intrand32: use % operator instead of (mathematically equivalent) + subtraction and multiplication, which can cause signed 32-bit + overflow. Report from Sam James diff --git a/doc/bash.1 b/doc/bash.1 index f8696707..41ae2084 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -10094,7 +10094,7 @@ arithmetic \fBfor\fP command, display the expanded value of .SM .BR PS4 , followed by the command and its expanded arguments -or associated word list. +or associated word list, to standard error. .TP 8 .B \-B The shell performs brace expansion (see diff --git a/doc/bashref.texi b/doc/bashref.texi index d419540e..3eb253e5 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -5455,9 +5455,9 @@ Print shell input lines as they are read. @item -x Print a trace of simple commands, @code{for} commands, @code{case} commands, @code{select} commands, and arithmetic @code{for} commands -and their arguments or associated word lists after they are -expanded and before they are executed. The value of the @env{PS4} -variable is expanded and the resultant value is printed before +and their arguments or associated word lists to standard error +after they are expanded and before they are executed. +The shell prints the expanded value of the @env{PS4} variable before the command and its expanded arguments. @item -B diff --git a/input.c b/input.c index 0e569e7d..76496cd5 100644 --- a/input.c +++ b/input.c @@ -464,6 +464,13 @@ set_buffered_stream (int fd, BUFFERED_STREAM *bp) return ret; } +/* Return the BUFFERED_STREAM associated with FD, if any. */ +BUFFERED_STREAM * +get_buffered_stream (int fd) +{ + return (buffers && fd < nbuffers) ? buffers[fd] : (BUFFERED_STREAM *)0; +} + /* Read a buffer full of characters from BP, a buffered stream. */ static int b_fill_buffer (BUFFERED_STREAM *bp) diff --git a/input.h b/input.h index 5fcfa743..f4d91b04 100644 --- a/input.h +++ b/input.h @@ -23,15 +23,6 @@ #include "stdc.h" -/* Function pointers can be declared as (Function *)foo. */ -#if !defined (_FUNCTION_DEF) -# define _FUNCTION_DEF -typedef int Function (); -typedef void VFunction (); -typedef char *CPFunction (); /* no longer used */ -typedef char **CPPFunction (); /* no longer used */ -#endif /* _FUNCTION_DEF */ - typedef int sh_cget_func_t (void); /* sh_ivoidfunc_t */ typedef int sh_cunget_func_t (int); /* sh_intfunc_t */ @@ -70,6 +61,12 @@ extern BUFFERED_STREAM **buffers; extern int default_buffered_input; extern int bash_input_fd_changed; +#undef beof +#undef berror + +#define beof(bp) (((bp)->b_flag & B_EOF) != 0) +#define berror(bp) (((bp)->b_flag & B_ERROR) != 0) + #endif /* BUFFERED_INPUT */ typedef union { @@ -122,6 +119,7 @@ extern int check_bash_input (int); extern int duplicate_buffered_stream (int, int); extern BUFFERED_STREAM *fd_to_buffered_stream (int); extern BUFFERED_STREAM *set_buffered_stream (int, BUFFERED_STREAM *); +extern BUFFERED_STREAM *get_buffered_stream (int); extern BUFFERED_STREAM *open_buffered_stream (char *); extern void free_buffered_stream (BUFFERED_STREAM *); extern int close_buffered_stream (BUFFERED_STREAM *); diff --git a/lib/readline/complete.c b/lib/readline/complete.c index c8f96e6f..fe0b8798 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -2037,9 +2037,25 @@ rl_complete_internal (int what_to_do) text = rl_copy_text (start, end); matches = gen_completion_matches (text, start, end, our_func, found_quote, quote_char); + /* If TEXT contains quote characters, it will be dequoted as part of + generating the matches, and the matches will not contain any quote + characters. We need to dequote TEXT before performing the comparison. + Since compare_match performs the dequoting, and we only want to do it + once, we don't call compare_matches after dequoting TEXT; we call + strcmp directly. */ /* nontrivial_lcd is set if the common prefix adds something to the word being completed. */ - nontrivial_lcd = matches && compare_match (text, matches[0]) != 0; + if (rl_filename_completion_desired && rl_filename_quoting_desired && + rl_completion_found_quote && rl_filename_dequoting_function) + { + char *t; + t = (*rl_filename_dequoting_function) (text, rl_completion_quote_character); + xfree (text); + text = t; + nontrivial_lcd = matches && strcmp (text, matches[0]) != 0; + } + else + nontrivial_lcd = matches && strcmp (text, matches[0]) != 0; if (what_to_do == '!' || what_to_do == '@') tlen = strlen (text); xfree (text); diff --git a/lib/sh/random.c b/lib/sh/random.c index d1b3df28..1fcd50e4 100644 --- a/lib/sh/random.c +++ b/lib/sh/random.c @@ -1,6 +1,6 @@ /* random.c -- Functions for managing 16-bit and 32-bit random numbers. */ -/* Copyright (C) 2020,2022 Free Software Foundation, Inc. +/* Copyright (C) 2020,2022,2023 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -75,7 +75,7 @@ intrand32 (u_bits32_t last) /* Can't seed with 0. */ ret = (last == 0) ? 123459876 : last; h = ret / 127773; - l = ret - (127773 * h); + l = ret % 127773; t = 16807 * l - 2836 * h; ret = (t < 0) ? t + 0x7fffffff : t; diff --git a/parse.y b/parse.y index e430f3aa..5786e14e 100644 --- a/parse.y +++ b/parse.y @@ -97,6 +97,10 @@ typedef void *alias_t; #define END_ALIAS -2 +#ifndef READERR +# define READERR -2 +#endif + #ifdef DEBUG # define YYDEBUG 1 #else @@ -2433,6 +2437,15 @@ shell_getc (int remove_quoted_newline) if (i == 0) shell_input_line_terminator = EOF; +#if defined (BUFFERED_INPUT) + if (i == 0) + { + BUFFERED_STREAM *bp; + bp = get_buffered_stream (default_buffered_input); + if (bp && berror (bp)) + shell_input_line_terminator = READERR; + } +#endif shell_input_line[i] = '\0'; break; @@ -2525,7 +2538,8 @@ shell_getc (int remove_quoted_newline) reason for the test against shell_eof_token, which is set to a right paren when parsing the contents of command substitutions. */ if (echo_input_at_read && (shell_input_line[0] || - shell_input_line_terminator != EOF) && + (shell_input_line_terminator != EOF && + shell_input_line_terminator != READERR)) && shell_eof_token == 0) fprintf (stderr, "%s\n", shell_input_line); } @@ -2540,7 +2554,7 @@ shell_getc (int remove_quoted_newline) /* Add the newline to the end of this string, iff the string does not already end in an EOF character. */ - if (shell_input_line_terminator != EOF) + if (shell_input_line_terminator != EOF && shell_input_line_terminator != READERR) { if (shell_input_line_size < SIZE_MAX-3 && (shell_input_line_len+3 > shell_input_line_size)) shell_input_line = (char *)xrealloc (shell_input_line, @@ -2676,6 +2690,9 @@ pop_alias: if (uc == 0 && shell_input_line_terminator == EOF) return ((shell_input_line_index != 0) ? '\n' : EOF); + else if (uc == 0 && shell_input_line_terminator == READERR) + /* Treat read errors like EOF here. */ + return ((shell_input_line_index != 0) ? '\n' : EOF); #if defined (ALIAS) || defined (DPAREN_ARITHMETIC) /* We already know that we are not parsing an alias expansion because of the