ash: fix obscure case of replacing + globbing + backslashes
No binary (build failed)
—
(log yok)
| @@ -6184,8 +6184,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |
| char *startp; | |
| char *loc; | |
| char *rmesc, *rmescend; | |
| - | IF_ASH_BASH_COMPAT(char *repl = NULL;) |
| - | IF_ASH_BASH_COMPAT(char null = '\0';) |
| + | IF_ASH_BASH_COMPAT(const char *repl = NULL;) |
| IF_ASH_BASH_COMPAT(int pos, len, orig_len;) | |
| int saveherefd = herefd; | |
| int amount, workloc, resetloc; | |
| @@ -6306,7 +6305,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |
| if (!repl) { | |
| repl = parse_sub_pattern(str, varflags & VSQUOTE); | |
| if (!repl) | |
| - | repl = &null; |
| + | repl = nullstr; |
| } | |
| /* If there's no pattern to match, return the expansion unmolested */ | |
| @@ -6357,8 +6356,12 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |
| idx = loc; | |
| } | |
| - | for (loc = repl; *loc; loc++) { |
| + | for (loc = (char*)repl; *loc; loc++) { |
| char *restart_detect = stackblock(); | |
| + | if (quotes && *loc == '\\') { |
| + | STPUTC(CTLESC, expdest); |
| + | len++; |
| + | } |
| STPUTC(*loc, expdest); | |
| if (stackblock() != restart_detect) | |
| goto restart; | |
| @@ -6368,6 +6371,10 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |
| if (subtype == VSREPLACE) { | |
| while (*idx) { | |
| char *restart_detect = stackblock(); | |
| + | if (quotes && *idx == '\\') { |
| + | STPUTC(CTLESC, expdest); |
| + | len++; |
| + | } |
| STPUTC(*idx, expdest); | |
| if (stackblock() != restart_detect) | |
| goto restart; | |
| @@ -6381,11 +6388,10 @@ subevalvar(char *p, char *str, int strloc, int subtype, | |
| /* We've put the replaced text into a buffer at workloc, now | |
| * move it to the right place and adjust the stack. | |
| */ | |
| - | startp = stackblock() + startloc; |
| STPUTC('\0', expdest); | |
| - | memmove(startp, stackblock() + workloc, len); |
| - | startp[len++] = '\0'; |
| - | amount = expdest - ((char *)stackblock() + startloc + len - 1); |
| + | startp = (char *)stackblock() + startloc; |
| + | memmove(startp, (char *)stackblock() + workloc, len + 1); |
| + | amount = expdest - (startp + len); |
| STADJUST(-amount, expdest); | |
| return startp; | |
| } | |
| @@ -6685,7 +6691,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |
| */ | |
| STPUTC('\0', expdest); | |
| patloc = expdest - (char *)stackblock(); | |
| - | if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype, |
| + | if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype, |
| startloc, varflags, | |
| //TODO: | EXP_REDIR too? All other such places do it too | |
| /* quotes: */ flags & (EXP_FULL | EXP_CASE), | |
| @@ -6848,13 +6854,11 @@ addfname(const char *name) | |
| exparg.lastp = &sp->next; | |
| } | |
| - | static char *expdir; |
| - | |
| /* | |
| * Do metacharacter (i.e. *, ?, [...]) expansion. | |
| */ | |
| static void | |
| - | expmeta(char *enddir, char *name) |
| + | expmeta(char *expdir, char *enddir, char *name) |
| { | |
| char *p; | |
| const char *cp; | |
| @@ -6953,7 +6957,7 @@ expmeta(char *enddir, char *name) | |
| for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) | |
| continue; | |
| p[-1] = '/'; | |
| - | expmeta(p, endname); |
| + | expmeta(expdir, p, endname); |
| } | |
| } | |
| } | |
| @@ -7035,6 +7039,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |
| /* TODO - EXP_REDIR */ | |
| while (str) { | |
| + | char *expdir; |
| struct strlist **savelastp; | |
| struct strlist *sp; | |
| char *p; | |
| @@ -7051,8 +7056,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |
| int i = strlen(str->text); | |
| expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ | |
| } | |
| - | |
| - | expmeta(expdir, p); |
| + | expmeta(expdir, expdir, p); |
| free(expdir); | |
| if (p != str->text) | |
| free(p); | |
| @@ -9101,19 +9105,15 @@ evalcommand(union node *cmd, int flags) | |
| /* Print the command if xflag is set. */ | |
| if (xflag) { | |
| int n; | |
| - | const char *p = " %s"; |
| + | const char *p = " %s" + 1; |
| - | p++; |
| fdprintf(preverrout_fd, p, expandstr(ps4val())); | |
| - | |
| sp = varlist.list; | |
| for (n = 0; n < 2; n++) { | |
| while (sp) { | |
| fdprintf(preverrout_fd, p, sp->text); | |
| sp = sp->next; | |
| - | if (*p == '%') { |
| - | p--; |
| - | } |
| + | p = " %s"; |
| } | |
| sp = arglist.list; | |
| } | |
| @@ -0,0 +1,10 @@ | |
| + | 192\.168\.0\.1 |
| + | 192\.168\.0\.1[ |
| + | 192\.168\.0\.1[ |
| + | 192\\.168\\.0\\.1[ |
| + | 192\.168\.0\.1[ |
| + | 192\.168\.0\.1 |
| + | 192\.168\.0\.1[ |
| + | 192\.168\.0\.1[ |
| + | 192\\.168\\.0\\.1[ |
| + | 192\.168\.0\.1[ |
| @@ -0,0 +1,21 @@ | |
| + | # The bug here was triggered by: |
| + | # * performin pathname expansion because we see [ |
| + | # * replace operator did not escape \ in replace string |
| + | |
| + | IP=192.168.0.1 |
| + | |
| + | rm -f '192.168.0.1[' |
| + | echo "${IP//./\\.}" |
| + | echo "${IP//./\\.}"'[' # bug was here |
| + | echo "${IP//./\\.}[" # bug was here |
| + | echo "${IP//./\\\\.}[" # bug was here |
| + | echo "192\.168\.0\.1[" |
| + | |
| + | echo >'192.168.0.1[' |
| + | echo "${IP//./\\.}" |
| + | echo "${IP//./\\.}"'[' # bug was here |
| + | echo "${IP//./\\.}[" # bug was here |
| + | echo "${IP//./\\\\.}[" # bug was here |
| + | echo "192\.168\.0\.1[" |
| + | |
| + | rm -f '192.168.0.1[' |