[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: EOF while in parse_matched_pair closes interactive shell
From: |
Eduardo A . Bustamante López |
Subject: |
Re: EOF while in parse_matched_pair closes interactive shell |
Date: |
Tue, 21 Feb 2023 12:59:26 -0800 |
On Tue, Feb 21, 2023 at 11:03:59AM -0500, Chet Ramey wrote:
(...)
> The shell should exit on EOF. Previous versions relied on undocumented
> bison behavior, which resulted in a token that wasn't handled by the
> grammar.
Thank you for reviewing this and for the explanation. I initially thought this
changed as a result of this change:
| parse.y
| - yylex: return YYUNDEF as current_token if read_token returns < 0.
| Fixes parser reset issue reported by Todd Stein <toddbstein@gmail.com>
| in https://savannah.gnu.org/support/index.php?110745
I changed `yylex' to return -1 the way it was, and it doesn't make a difference
in this case.
By luck, I found that removing this line reverts to the original behavior:
$ git diff -- parse.y
diff --git a/parse.y b/parse.y
index 9178e9a7..87d45ac1 100644
--- a/parse.y
+++ b/parse.y
@@ -3714,7 +3714,7 @@ parse_matched_pair (int qc, int open, int close, size_t
*lenp, int flags)
free (ret);
parser_error (start_lineno, _("unexpected EOF while looking for
matching `%c'"), close);
EOF_Reached = 1; /* XXX */
- parser_state |= PST_NOERROR; /* avoid redundant error message */
+ /*parser_state |= PST_NOERROR;*/ /* avoid redundant error
message */
return (&matched_pair_error);
}
My understanding of how this works is as follows. The unexpected EOF causes
`parse_matched_pair' to return an error, which eventually leads to a call to
`yyerror'. In `yyerror', we call `report_syntax_error' _only if_ the NOERROR
parser flag is off. Despite its name, `report_syntax_error' does more than
that. It'll actually clear `EOF_Reached' when the shell is interactive:
bash: syntax error: unexpected end of file
6458 if (interactive && EOF_Reached)
6459 EOF_Reached = 0;
6462 last_command_exit_value = (executing_builtin &&
parse_and_execute_level) ? EX_BADSYNTAX : EX_BADUSAGE;
The parser eventually makes it way back to `reader_loop'. In 5.2, EOF_Reached is
1 at that point. In 5.1, it's 0 as it was cleared by `report_syntax_error'.
Knowing this now, I was able to find the commit that changed this, and the note
explaining the change:
| commit b48c234286ae692c758306dac26a5bb72f782fef
| Date: Mon Oct 31 10:08:36 2022 -0400
| (...)
| parse.y
| - parse_matched_pair: set PST_NOERROR if we read to EOF without finding
| a closing match and call parser_error; avoids redundant error
| message
As an aside, this change also restores the original behavior:
$ git diff -- parse.y
diff --git a/parse.y b/parse.y
index 9178e9a7..d2d20874 100644
--- a/parse.y
+++ b/parse.y
@@ -3713,7 +3713,7 @@ parse_matched_pair (int qc, int open, int close, size_t
*lenp, int flags)
{
free (ret);
parser_error (start_lineno, _("unexpected EOF while looking for
matching `%c'"), close);
- EOF_Reached = 1; /* XXX */
+ /*EOF_Reached = 1;*/ /* XXX */
parser_state |= PST_NOERROR; /* avoid redundant error message */
return (&matched_pair_error);
}
In any case, I do understand why you've made this change. I've checked how bash
deals with an EOF while parsing other partial commands (e.g. `if', `for x in',
`echo $(') and these all behave in the same way. So I don't disagree. I just
thought I should share my troubleshooting notes.
> If there's a bug here, it's that interactive shells need to handle
> IGNOREEOF in this case.
Thanks for reminding me about IGNOREEOF. It does seem like `parse_matched_pair'
doesn't work with `ignoreeof' in this case. I suppose that's because the parser
doesn't see `yacc_EOF', so it never calls `handle_eof_input_unit'.