Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260805141033.841558-4-matthias.goergens@gmail.com>
Date: Wed,  5 Aug 2026 22:10:26 +0800
From: Matthias Goergens <matthias.goergens@...il.com>
To: musl@...ts.openwall.com
Cc: Matthias Goergens <matthias.goergens@...il.com>
Subject: [PATCH 03/10] regression: test scanf field width overflow

Field widths through INT_MAX must reach normal conversion; larger
widths must be rejected as an invalid format instead of wrapping to
a small or negative value. The accumulation must not overflow even
intermediately, as it first did at the valid width 2147483600.

Covered by the musl patch "stdio: avoid field width overflow in
scanf".
---
 src/regression/scanf-field-width-overflow.c | 59 +++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 src/regression/scanf-field-width-overflow.c

diff --git a/src/regression/scanf-field-width-overflow.c b/src/regression/scanf-field-width-overflow.c
new file mode 100644
index 0000000..0e58757
--- /dev/null
+++ b/src/regression/scanf-field-width-overflow.c
@@ -0,0 +1,59 @@
+// scanf field widths were accumulated in int as 10*width + *p - '0',
+// which can overflow even when the final decimal value fits (first at
+// the valid width 2147483600, because the digit character is added
+// before '0' is subtracted). Widths through INT_MAX must be accepted;
+// larger widths must be rejected as an invalid format instead of
+// wrapping to a small or negative value.
+#include <limits.h>
+#include <stdio.h>
+#include <wchar.h>
+#include "test.h"
+
+struct narrow_case {
+	const char *format;
+	int expected;
+};
+
+struct wide_case {
+	const wchar_t *format;
+	int expected;
+};
+
+int main(void)
+{
+	char dummy;
+	static const struct narrow_case narrow[] = {
+		/* clean widths: reach normal conversion, input "x" matches once */
+		{"%*2147483599c", 0},
+		{"%*2147483600c", 0}, /* intermediate overflow boundary */
+		{"%*2147483647c", 0}, /* INT_MAX */
+		/* overlarge widths: invalid format, EOF, no input consumed */
+		{"%*2147483648c", EOF},
+		{"%*9999999999999999999999999999999999999999c", EOF},
+	};
+	static const struct wide_case wide[] = {
+		{L"%*2147483599c", 0},
+		{L"%*2147483600c", 0},
+		{L"%*2147483647c", 0},
+		{L"%*2147483648c", EOF},
+		{L"%*9999999999999999999999999999999999999999c", EOF},
+	};
+	size_t i;
+	int r;
+
+	for (i = 0; i < sizeof narrow / sizeof narrow[0]; i++) {
+		r = sscanf("x", narrow[i].format, &dummy);
+		if (r != narrow[i].expected)
+			t_error("sscanf(\"x\", \"%s\") = %d, want %d\n",
+				narrow[i].format, r, narrow[i].expected);
+	}
+	for (i = 0; i < sizeof wide / sizeof wide[0]; i++) {
+		r = swscanf(L"x", wide[i].format, &dummy);
+		if (r != wide[i].expected)
+			t_error("swscanf(L\"x\", L\"%ls\") = %d, want %d\n",
+				wide[i].format, r, wide[i].expected);
+	}
+	if (2147483647 != INT_MAX)
+		t_error("test assumes 32-bit int\n");
+	return t_status;
+}
-- 
2.55.0

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.