>From 6dd466eda6fa3f1f7d2a9474ec926ccd2ede98e9 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 26 Mar 2021 13:49:49 -0700 Subject: [PATCH] env: fix address violation with '\v' in -S Problem reported by Frank Busse (Bug#47412). * src/env.c (C_ISSPACE_CHARS): New macro. (shortopts, build_argv, main): Treate all C-locale space characters like space and tab, for compatibility with FreeBSD. (validate_split_str, build_argv, parse_split_string): Use the C locale, not the current locale, to determine whether a byte is a space character. --- src/env.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/env.c b/src/env.c index ba9da1113..e13a312cd 100644 --- a/src/env.c +++ b/src/env.c @@ -73,7 +73,10 @@ static bool sig_mask_changed; /* Whether to list non default handling. */ static bool report_signal_handling; -static char const shortopts[] = "+C:iS:u:v0 \t"; +/* isspace characters in the C locale. */ +#define C_ISSPACE_CHARS " \t\n\v\f\r" + +static char const shortopts[] = "+C:iS:u:v0" C_ISSPACE_CHARS; /* For long options that have no equivalent short option, use a non-character as a pseudo short option, starting with CHAR_MAX + 1. */ @@ -277,7 +280,7 @@ validate_split_str (const char* str, size_t* /*out*/ bufsize, size_t buflen; int cnt = 1; - assert (str && str[0] && !isspace (str[0])); /* LCOV_EXCL_LINE */ + assert (str && str[0] && !c_isspace (str[0])); /* LCOV_EXCL_LINE */ dq = sq = sp = false; buflen = strlen (str)+1; @@ -286,7 +289,7 @@ validate_split_str (const char* str, size_t* /*out*/ bufsize, { const char next = *(str+1); - if (isspace (*str) && !dq && !sq) + if (c_isspace (*str) && !dq && !sq) { sp = true; } @@ -392,7 +395,7 @@ build_argv (const char* str, int extra_argc) } \ } while (0) - assert (str && str[0] && !isspace (str[0])); /* LCOV_EXCL_LINE */ + assert (str && str[0] && !c_isspace (str[0])); /* LCOV_EXCL_LINE */ validate_split_str (str, &buflen, &newargc); @@ -433,13 +436,12 @@ build_argv (const char* str, int extra_argc) ++str; continue; - case ' ': - case '\t': - /* space/tab outside quotes starts a new argument. */ + case ' ': case '\t': case '\n': case '\v': case '\f': case '\r': + /* Start a new argument if outside quotes. */ if (sq || dq) break; sep = true; - str += strspn (str, " \t"); /* skip whitespace. */ + str += strspn (str, C_ISSPACE_CHARS); continue; case '#': @@ -540,7 +542,7 @@ parse_split_string (const char* str, int /*out*/ *orig_optind, char **newargv, **nextargv; - while (isspace (*str)) + while (c_isspace (*str)) str++; if (*str == '\0') return; @@ -848,8 +850,7 @@ main (int argc, char **argv) case 'S': parse_split_string (optarg, &optind, &argc, &argv); break; - case ' ': - case '\t': + case ' ': case '\t': case '\n': case '\v': case '\f': case '\r': /* These are undocumented options. Attempt to detect incorrect shebang usage with extraneous space, e.g.: #!/usr/bin/env -i command -- 2.30.2