From dcd95d8a010c87b954128824c40a6cb3b28a3688 Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Fri, 19 Feb 2016 21:53:12 +0000 Subject: sh: Rework code to remove '\0' from shell input. This fixes bugs where '\0' was not removed correctly and speeds up the parser. --- bin/sh/input.c | 52 ++++++++++++++++++++------------------------ bin/sh/tests/parser/Makefile | 1 + bin/sh/tests/parser/nul1.0 | 12 ++++++++++ 3 files changed, 37 insertions(+), 28 deletions(-) create mode 100644 bin/sh/tests/parser/nul1.0 diff --git a/bin/sh/input.c b/bin/sh/input.c index 412f1442b08c..5921e082da09 100644 --- a/bin/sh/input.c +++ b/bin/sh/input.c @@ -195,8 +195,7 @@ retry: int preadbuffer(void) { - char *p, *q; - int more; + char *p, *q, *r, *end; char savec; while (parsefile->strpush) { @@ -224,34 +223,31 @@ again: } } - q = p = parsefile->buf + (parsenextc - parsefile->buf); - - /* delete nul characters */ - for (more = 1; more;) { - switch (*p) { - case '\0': - p++; /* Skip nul */ - goto check; - - case '\n': - parsenleft = q - parsenextc; - more = 0; /* Stop processing here */ - break; - - default: - break; - } - - *q++ = *p++; -check: - if (--parselleft <= 0) { - parsenleft = q - parsenextc - 1; - if (parsenleft < 0) - goto again; - *q = '\0'; - more = 0; + p = parsefile->buf + (parsenextc - parsefile->buf); + end = p + parselleft; + *end = '\0'; + q = strchrnul(p, '\n'); + if (q != end && *q == '\0') { + /* delete nul characters */ + for (r = q; q != end; q++) { + if (*q != '\0') + *r++ = *q; } + parselleft -= end - r; + if (parselleft == 0) + goto again; + end = p + parselleft; + *end = '\0'; + q = strchrnul(p, '\n'); + } + if (q == end) { + parsenleft = parselleft; + parselleft = 0; + } else /* *q == '\n' */ { + parsenleft = q - parsenextc + 1; + parselleft -= parsenleft; } + parsenleft--; savec = *q; *q = '\0'; diff --git a/bin/sh/tests/parser/Makefile b/bin/sh/tests/parser/Makefile index 78a0734d9be7..eb1e6f567b5c 100644 --- a/bin/sh/tests/parser/Makefile +++ b/bin/sh/tests/parser/Makefile @@ -73,6 +73,7 @@ FILES+= line-cont10.0 FILES+= line-cont11.0 FILES+= no-space1.0 FILES+= no-space2.0 +FILES+= nul1.0 FILES+= only-redir1.0 FILES+= only-redir2.0 FILES+= only-redir3.0 diff --git a/bin/sh/tests/parser/nul1.0 b/bin/sh/tests/parser/nul1.0 new file mode 100644 index 000000000000..49c5ab1b0cfb --- /dev/null +++ b/bin/sh/tests/parser/nul1.0 @@ -0,0 +1,12 @@ +# $FreeBSD$ +# Although POSIX does not specify the effect of NUL bytes in scripts, +# we ignore them. + +{ + printf 'v=%03000d\0%02000d' 7 2 + dd if=/dev/zero bs=1000 count=1 status=none + printf '1 w=%03000d%02000d1\0\n' 7 2 + printf '\0l\0v\0=\0$\0{\0#\0v\0}\n' + printf '\0l\0w\0=\0\0$\0{\0#\0w}\0\0\0\n' + printf '[ "$lv.$lw.$v" = "5001.5001.$w" ]\n' +} | ${SH} -- cgit v1.2.3