Skip to content

Commit

Permalink
Fix wrong syntax error upon process substitution after redirection
Browse files Browse the repository at this point in the history
Grammatically, redirections may occur anywhere within a command
line and are removed after processing them, whereas a process
substitution (<(commandlist) or >(commandlist)) is replaced by a
file name which should be treated as just another simple word.
So the following should not be a syntax error:

$ cat </dev/null <(true)
-ksh: syntax error: `)' unexpected
$ cat </dev/null >(true)
-ksh: syntax error: `)' unexpected
$ cat >/dev/null <(true)
-ksh: syntax error: `)' unexpected
$ cat >/dev/null >(true)
-ksh: syntax error: `)' unexpected

This bug is in every ksh93 version.

The problem is in the parser (parse.c). The process substitution is
misparsed as a redirection due to inout() recursively parsing
multiple redirections without recognising process substitutions.
inout() is mistaking '<(' for '<' and '>(' for '>', which explains
the incorrect syntax error.

This also causes the following to fail to detect a syntax error:
$ cat >&1 <(README.md
[the contents of README.md are shown]

...and other syntax errors detected in the wrong spot, for example:
$ { true; } <(echo wrong)
-ksh: syntax error: `wrong' unexpected
which should be:
-ksh: syntax error: `<(' unexpected

src/cmd/ksh93/sh/parse.c:
- Add global inout_found_procsub flag.
- inout(): On encountering a process substitution, set this flag
  and return, otherwise clear the flag.
- simple(): After calling inout(), check this flag and, if set,
  jump back to where process substitutions are parsed.

Resolves: #418
  • Loading branch information
McDutchie committed Jul 5, 2022
1 parent 8a0920e commit 06e5625
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 1 deletion.
6 changes: 6 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0

Any uppercase BUG_* names are modernish shell bug IDs.

2022-07-05:

- Fixed a spurious syntax error on encountering a process substitution
following a redirection without being an argument to a redirection.
For example, this now writes 'OK' to standard error: cat >&2 <(echo OK)

2022-07-02:

- Fixed a bug where, if the last command in a subshell was an external
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/ksh93/include/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
#define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */
#define SH_RELEASE_DATE "2022-07-02" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_DATE "2022-07-05" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_CPYR "(c) 2020-2022 Contributors to ksh " SH_RELEASE_FORK

/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
Expand Down
7 changes: 7 additions & 0 deletions src/cmd/ksh93/sh/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ static Shnode_t *makeparent(Lex_t*, int, Shnode_t*);
static Shnode_t *makelist(Lex_t*, int, Shnode_t*, Shnode_t*);
static struct argnod *qscan(struct comnod*, int);
static struct ionod *inout(Lex_t*,struct ionod*, int);
static char inout_found_procsub;
static Shnode_t *sh_cmd(Lex_t*,int,int);
static Shnode_t *term(Lex_t*,int);
static Shnode_t *list(Lex_t*,int);
Expand Down Expand Up @@ -1583,6 +1584,7 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
lexp->token = tok = 0;
if((tok==IPROCSYM || tok==OPROCSYM))
{
procsub:
argp = process_sub(lexp,tok);
argno = -1;
*argtail = argp;
Expand Down Expand Up @@ -1655,6 +1657,8 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
}
else
t->comio = io = inout(lexp,(struct ionod*)0,0);
if(inout_found_procsub)
goto procsub;
}
}
*argtail = 0;
Expand Down Expand Up @@ -1753,6 +1757,9 @@ static struct ionod *inout(Lex_t *lexp,struct ionod *lastio,int flag)
Stk_t *stkp = sh.stk;
char *iovname=0;
register int errout=0;
/* return if a process substitution is found without a redirection */
if(inout_found_procsub = (token==IPROCSYM || token==OPROCSYM))
return(lastio);
if(token==IOVNAME)
{
iovname=lexp->arg->argval+1;
Expand Down
30 changes: 30 additions & 0 deletions src/cmd/ksh93/tests/io.sh
Original file line number Diff line number Diff line change
Expand Up @@ -974,5 +974,35 @@ then
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
fi
# ======
# A process substitution should be valid after a redirection
# https://github.com/ksh93/ksh/issues/418
got=$(set +x; eval ': </dev/null <(true)' 2>&1)
[[ e=$? -eq 0 && -z $got ]] || err_exit "spurious syntax error on process substitution following redirection" \
"(expected status 0 and '', got status $e and $(printf %q "$got"))"
got=$(set +x; eval ': <&1 <(/dev/null' 2>&1)
exp='*: syntax error at line *: `end of file'\'' unexpected'
[[ $got == $exp ]] || err_exit "': <&1 <(/dev/null' fails to throw a syntax error" \
"(expected match of $(printf %q "$exp"), got $(printf %q "$got"))"
got=$(set +x; eval '{ :; } <(: wrong)' 2>&1)
exp='*: syntax error at line *: `<('\'' unexpected'
[[ $got == $exp ]] || err_exit "'{ :; } <(: wrong)' throws incorrect syntax error" \
"(expected match of $(printf %q "$exp"), got $(printf %q "$got"))"
got=$(set +x; eval ': >/dev/null >(true)' 2>&1)
[[ e=$? -eq 0 && -z $got ]] || err_exit "spurious syntax error on process substitution following redirection" \
"(expected status 0 and '', got status $e and $(printf %q "$got"))"
got=$(set +x; eval ': >&1 >(/dev/null' 2>&1)
exp='*: syntax error at line *: `end of file'\'' unexpected'
[[ $got == $exp ]] || err_exit "': >&1 >(/dev/null' fails to throw a syntax error" \
"(expected match of $(printf %q "$exp"), got $(printf %q "$got"))"
got=$(set +x; eval '{ :; } >(: wrong)' 2>&1)
exp='*: syntax error at line *: `>('\'' unexpected'
[[ $got == $exp ]] || err_exit "'{ :; } >(: wrong)' throws incorrect syntax error" \
"(expected match of $(printf %q "$exp"), got $(printf %q "$got"))"
got=$(set +x; eval 'cat >out <(echo OK)' 2>&1; echo ===; cat out)
exp=$'===\nOK'
[[ $got == "$exp" ]] || err_exit "process substitution nixes output redirection" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# ======
exit $((Errors<125?Errors:125))

0 comments on commit 06e5625

Please sign in to comment.