Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251205043945.19881-1-idodo4nm@proton.me>
Date: Fri,  5 Dec 2025 11:39:45 +0700
From: mamutrahal269 <levrymvc@...il.com>
To: musl@...ts.openwall.com
Cc: mamutrahal269 <idodo4nm@...ton.me>
Subject: [PATCH] POSIX positional arg numbering (1-based) and multi-digit support in printf_core, raise NL_ARGMAX to 255

The positional argument parsing logic in printf_core was reworked: instead of only accepting single-digit
positional indices, the code now uses getint() to read multi-digit numbers and checks for the terminating $.
The old logic isdigit(s[1]) && s[2]=='$' was replaced with proper multi-digit parsing to support numbers
larger than 9. Additional validation was added to reject zero as an argument index and to detect overflow
when the index exceeds NL_ARGMAX. Similar multi-digit parsing was implemented for width and precision
arguments using * with positional indices. Finally, NL_ARGMAX was increased from 9 to 255 in limits.h
to match the expanded positional argument range.

Signed-off-by: mamutrahal269 <idodo4nm@...ton.me>
---
 include/limits.h     |  2 +-
 src/stdio/vfprintf.c | 38 ++++++++++++++++++++++----------------
 2 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/include/limits.h b/include/limits.h
index 53a27b9d..760eb745 100644
--- a/include/limits.h
+++ b/include/limits.h
@@ -84,7 +84,7 @@
 #define LINE_MAX 4096
 #define RE_DUP_MAX 255
 
-#define NL_ARGMAX 9
+#define NL_ARGMAX 255
 #define NL_MSGMAX 32767
 #define NL_SETMAX 255
 #define NL_TEXTMAX 2048
diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
index 514a44dd..e738e77f 100644
--- a/src/stdio/vfprintf.c
+++ b/src/stdio/vfprintf.c
@@ -429,11 +429,11 @@ static int getint(char **s) {
 
 static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
 {
-	char *a, *z, *s=(char *)fmt;
+	char *a, *z, *s1, *s=(char *)fmt;
 	unsigned l10n=0, fl;
 	int w, p, xp;
 	union arg arg;
-	int argpos;
+	int argpos, pos;
 	unsigned st, ps;
 	int cnt=0, l=0;
 	size_t i;
@@ -461,13 +461,14 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
 		if (f) out(f, a, l);
 		if (l) continue;
 
-		if (isdigit(s[1]) && s[2]=='$') {
+		s1 = ++s;
+		if ((argpos = getint(&s1)) >= 0 && *s1=='$') {
+			if (argpos > NL_ARGMAX) goto overflow;
+			if (!argpos) goto inval;
 			l10n=1;
-			argpos = s[1]-'0';
-			s+=3;
+			s = s1 + 1;
 		} else {
 			argpos = -1;
-			s++;
 		}
 
 		/* Read modifier flags */
@@ -476,27 +477,32 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
 
 		/* Read field width */
 		if (*s=='*') {
-			if (isdigit(s[1]) && s[2]=='$') {
+			s1 = ++s;
+			if ((pos = getint(&s1)) >= 0 && *s1=='$') {
+				if (pos > NL_ARGMAX) goto overflow;
+				if (!pos) goto inval;
 				l10n=1;
-				if (!f) nl_type[s[1]-'0'] = INT, w = 0;
-				else w = nl_arg[s[1]-'0'].i;
-				s+=3;
+				s = s1 + 1;
+				if (!f) nl_type[pos] = INT, w = 0;
+				else w = nl_arg[pos].i;
 			} else if (!l10n) {
 				w = f ? va_arg(*ap, int) : 0;
-				s++;
 			} else goto inval;
 			if (w<0) fl|=LEFT_ADJ, w=-w;
 		} else if ((w=getint(&s))<0) goto overflow;
 
 		/* Read precision */
 		if (*s=='.' && s[1]=='*') {
-			if (isdigit(s[2]) && s[3]=='$') {
-				if (!f) nl_type[s[2]-'0'] = INT, p = 0;
-				else p = nl_arg[s[2]-'0'].i;
-				s+=4;
+			s+=2;
+			s1 = s;
+			if ((pos = getint(&s1)) >= 0 && *s1=='$') {
+				if (pos > NL_ARGMAX) goto overflow;
+				if (!pos) goto inval;
+				s = s1 + 1;
+				if (!f) nl_type[pos] = INT, p = 0;
+				else p = nl_arg[pos].i;
 			} else if (!l10n) {
 				p = f ? va_arg(*ap, int) : 0;
-				s+=2;
 			} else goto inval;
 			xp = (p>=0);
 		} else if (*s=='.') {
-- 
2.47.3

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.