summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Brown <opensource@whoopdedo.org>2015-12-06 15:09:42 +0100
committerHerbert Xu <herbert@gondor.apana.org.au>2016-06-06 18:32:56 +0800
commit0134f725b7d254ddbc3cc6dd72399edea832559c (patch)
treea425bdc2019436e278fc224635a25ae0a2d49dc9
parentRelease 0.5.9. (diff)
downloaddash-0134f725b7d254ddbc3cc6dd72399edea832559c.tar.gz
dash-0134f725b7d254ddbc3cc6dd72399edea832559c.zip
builtin: Reject malformed printf specifications with digits after '*'
Dash doesn't notice when a format string has digits following a * width
specifier.

    $ dash -c 'printf "%*0s  " 1 2 && echo FAIL || echo OK'
    %10s  FAIL

    $ bash -c 'printf "%*0s  " 1 2 && echo FAIL || echo OK'
    bash: line 0: printf: `0': invalid format character
    OK
    $ mksh -c 'printf "%*0s  " 1 2 && echo FAIL || echo OK'
    printf: %*0: invalid conversion specification
    OK

With this patch dash complains about the malformed specifications.

    $ ./src/dash -c 'printf "%*0s  " 1 2 && echo FAIL || echo OK'
    ./src/dash: 1: printf: %*0: invalid directive
    OK

Fixes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=779618

Originally-by: Patrick Brown <opensource@whoopdedo.org>
Forwarded-by: Gioele Barabucci <gioele@svario.it>

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--src/bltin/printf.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/src/bltin/printf.c b/src/bltin/printf.c
index 9673e10..1112253 100644
--- a/src/bltin/printf.c
+++ b/src/bltin/printf.c
@@ -175,17 +175,24 @@ pc:
 
 			/* skip to field width */
 			fmt += strspn(fmt, SKIP1);
-			if (*fmt == '*')
-				*param++ = getuintmax(1);
-
-			/* skip to possible '.', get following precision */
-			fmt += strspn(fmt, SKIP2);
-			if (*fmt == '.')
+			if (*fmt == '*') {
 				++fmt;
-			if (*fmt == '*')
 				*param++ = getuintmax(1);
+			} else {
+				/* skip to possible '.',
+				 * get following precision
+				 */
+				fmt += strspn(fmt, SKIP2);
+			}
 
-			fmt += strspn(fmt, SKIP2);
+			if (*fmt == '.') {
+				++fmt;
+				if (*fmt == '*') {
+					++fmt;
+					*param++ = getuintmax(1);
+				} else
+					fmt += strspn(fmt, SKIP2);
+			}
 
 			ch = *fmt;
 			if (!ch)