From 9990355ff8b3569ba1cce9853781d6fe1cab09db Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 11 Jun 2023 18:06:50 -0500 Subject: [PATCH] Fix HERE document quoting, remove deletion list from expand_one_arg() (have it free its own temporary memory instead, and callers free the result when it != the argument passed in), add some tests. --- tests/sh.test | 14 +++++++++++--- toys/pending/sh.c | 38 ++++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/tests/sh.test b/tests/sh.test index e7bdc698..5dd4d4f4 100644 --- a/tests/sh.test +++ b/tests/sh.test @@ -108,6 +108,15 @@ testing 'trailing $ is literal' 'echo $' '$\n' '' '' testing 'work after HERE' $'cat<<0;echo hello\npotato\n0' 'potato\nhello\n' '' '' testing '<<""' $'cat<<"";echo hello\npotato\n\necho huh' 'potato\nhello\nhuh\n'\ '' '' +ln -s "$(which echo)" echo2 +testing "undelimited redirect doesn't eat prefix" './echo2next; + if (del->arg != s) free(del->arg); + free(del); + del = dd; + } free(arg.v); return s; @@ -2580,13 +2589,13 @@ static struct sh_process *expand_redir(struct sh_arg *arg, int skip, int *urd) // HERE documents? if (!strncmp(ss, "<<", 2)) { char *tmp = xmprintf("%s/sh-XXXXXX", getvar("TMPDIR") ? : "/tmp"); - int i, len, zap = (ss[2] == '-'), x = !ss[strcspn(ss, "\"'")]; + int i, h, len, zap = (ss[2] == '-'), x = !sss[strcspn(sss, "\\\"'")]; // store contents in open-but-deleted /tmp file: write then lseek(start) if ((from = mkstemp(tmp))>=0) { if (unlink(tmp)) bad++; else if (ss[2] == '<') { // not stored in arg[here] - if (!(ss = expand_one_arg(sss, 0, 0))) { + if (!(ss = expand_one_arg(sss, 0))) { s = 0; break; } @@ -2598,19 +2607,18 @@ static struct sh_process *expand_redir(struct sh_arg *arg, int skip, int *urd) struct sh_arg *hh = arg+ ++here; for (i = 0; ic; i++) { - ss = hh->v[i]; - sss = 0; + sss = ss = hh->v[i]; + while (zap && *ss == '\t') ss++; // TODO audit this ala man page // expand_parameter, commands, and arithmetic - if (x && !(sss = expand_one_arg(ss, ~SEMI_IFS, 0))) { + if (x && !(sss = expand_one_arg(ss, ~SEMI_IFS))) { s = 0; break; } - while (zap && *ss == '\t') ss++; - x = writeall(from, ss, len = strlen(ss)); + h = writeall(from, sss, len = strlen(sss)); if (ss != sss) free(sss); - if (len != x) break; + if (len != h) break; } if (i != hh->c) bad++; } @@ -2804,13 +2812,14 @@ static struct sh_process *run_command(void) if (envlen) for (; jjexit; jj++) { struct sh_vars *vv; - if ((sss = expand_one_arg(ss = arg->v[jj], SEMI_IFS, 0))) { + if ((sss = expand_one_arg(ss = arg->v[jj], SEMI_IFS))) { if (!prefix && sss==ss) sss = xstrdup(sss); if ((vv = setvar_long(sss, sss!=ss, prefix ? TT.ff : TT.ff->prev))) { if (prefix) vv->flags |= VAR_EXPORT; continue; } } + pp->exit = 1; break; } @@ -3829,8 +3838,9 @@ static void run_lines(void) // TODO: bash man page says it performs <(process substituion) here?!? } else if (!strcmp(s, "case")) { - TT.ff->blk->fvar = expand_one_arg(ss, NO_NULL, &TT.ff->blk->fdelete); - if (!TT.ff->blk->fvar) break; + if (!(TT.ff->blk->fvar = expand_one_arg(ss, NO_NULL))) break; + if (ss != TT.ff->blk->fvar) + push_arg(&TT.ff->blk->fdelete, TT.ff->blk->fvar); } // TODO [[/]] ((/)) function/} @@ -4551,7 +4561,7 @@ void eval_main(void) call_function(); TT.ff->arg.v = toys.argv; TT.ff->arg.c = toys.optc+1; - s = expand_one_arg("\"$*\"", SEMI_IFS, 0); + s = expand_one_arg("\"$*\"", SEMI_IFS); TT.ff->arg.v = TT.ff->next->arg.v; TT.ff->arg.c = TT.ff->next->arg.c; do_source(0, fmemopen(s, strlen(s), "r")); -- 2.39.2