sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

commit ae7bfda8f6f1b3f1951e8e69b8910d5171bf6236
parent 87f4755cd09eecdab7c750a347143cc6fb3b262d
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date:   Wed,  5 Nov 2025 09:59:44 +0100

grep: Don't modify constant strings

The pattern pointer was assigned to a constant string and later it was
modified, which is UB. But even worse, as we were trusting the patlen
parameter received, patlen was meaningless after that assignment.

The addpattern() had many problems because it trusted the patlen
parameter, but in some places it used string functions that depend of
having a NUL character creating many problems when embedded NUL characters
were found in the pattern. As mandated by POSIX in [1]:

	The interfaces specified in POSIX.1-2017 do not permit the
	inclusion of a NUL character in an RE or in the string to be
	matched. If during the operation of a standard utility a NUL
	is included in the text designated to be matched, that NUL may
	designate the end of the text string for the purposes of matching.

so, the simples solution is just discard the patlen parameter and call
strlen() in addpattern() and use that as size of the pattern.

[1] https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html

Co-authored-by: Santtu Lakkala <inz@inz.fi>

Diffstat:
Mgrep.c | 28+++++++++-------------------
1 file changed, 9 insertions(+), 19 deletions(-)

diff --git a/grep.c b/grep.c @@ -10,7 +10,7 @@ enum { Match = 0, NoMatch = 1, Error = 2 }; -static void addpattern(const char *, size_t); +static void addpattern(const char *); static void addpatternfile(FILE *); static int grep(FILE *, const char *); @@ -37,37 +37,27 @@ struct pattern { static SLIST_HEAD(phead, pattern) phead; static void -addpattern(const char *pattern, size_t patlen) +addpattern(const char *pattern) { struct pattern *pnode; char *tmp; int bol, eol; - size_t len; + size_t len, patlen; - if (!patlen) - return; - - /* a null BRE/ERE matches every line */ - if (!Fflag) - if (pattern[0] == '\0') - pattern = "^"; + patlen = strlen(pattern); + bol = pattern[0] == '^'; + eol = patlen > 0 && pattern[patlen - 1] == '$') if (!Fflag && xflag) { tmp = enmalloc(Error, patlen + 3); snprintf(tmp, patlen + 3, "%s%s%s", - pattern[0] == '^' ? "" : "^", + bol ? "" : "^", pattern, - pattern[patlen - 1] == '$' ? "" : "$"); + eol ? "" : "$"); } else if (!Fflag && wflag) { len = patlen + 5 + (Eflag ? 2 : 4); tmp = enmalloc(Error, len); - bol = eol = 0; - if (pattern[0] == '^') - bol = 1; - if (pattern[patlen - 1] == '$') - eol = 1; - snprintf(tmp, len, "%s\\<%s%.*s%s\\>%s", bol ? "^" : "", Eflag ? "(" : "\\(", @@ -93,7 +83,7 @@ addpatternfile(FILE *fp) while ((len = getline(&buf, &size, fp)) > 0) { if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; - addpattern(buf, (size_t)len); + addpattern(buf); } if (ferror(fp)) enprintf(Error, "read error:");