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-9-matthias.goergens@gmail.com>
Date: Wed,  5 Aug 2026 22:10:31 +0800
From: Matthias Goergens <matthias.goergens@...il.com>
To: musl@...ts.openwall.com
Cc: Matthias Goergens <matthias.goergens@...il.com>
Subject: [PATCH 08/10] regression: test strptime year overflow

The year inside %F has unlimited width, so long inputs must not
overflow the accumulator and falsely succeed with a corrupted
tm_year; %C composition is checked too. The exact representable
tm_year boundaries must still be accepted.

Covered by the musl patch "time: reject overflowing strptime
years".
---
 src/regression/strptime-year-overflow.c | 59 +++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 src/regression/strptime-year-overflow.c

diff --git a/src/regression/strptime-year-overflow.c b/src/regression/strptime-year-overflow.c
new file mode 100644
index 0000000..03413e7
--- /dev/null
+++ b/src/regression/strptime-year-overflow.c
@@ -0,0 +1,59 @@
+// strptime accumulated numeric year fields directly in int. The year
+// inside %F has unlimited width (POSIX.1-2024), so long inputs
+// overflowed the accumulator and falsely succeeded with a corrupted
+// tm_year; %C combined with %y could overflow too. Overlarge years
+// must fail conversion; the exact representable tm_year boundaries
+// must still be accepted.
+#define _XOPEN_SOURCE
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+#include <time.h>
+#include "test.h"
+
+struct test {
+	const char *input;
+	const char *format;
+	ptrdiff_t end; /* expected end offset, -1 for conversion failure */
+	int year;      /* expected tm_year when end >= 0 */
+};
+
+int main(void)
+{
+	static const struct test tests[] = {
+		/* overlarge years: conversion failure */
+		{ "99999999999-01-01", "%F", -1, 0 },
+		{ "99999999999", "%11Y", -1, 0 },
+		{ "2147485548", "%10Y", -1, 0 },
+		{ "-2147481749", "%10Y", -1, 0 },
+		{ "21474856", "%8C", -1, 0 },
+		{ "-21474836", "%8C", -1, 0 },
+		/* exact tm_year boundaries: accepted */
+		{ "2147485547", "%10Y", 10, INT_MAX },
+		{ "-2147481748", "%10Y", 11, INT_MIN },
+		/* ordinary conversions */
+		{ "2026", "%Y", 4, 126 },
+		{ "2026-08-02", "%F", 10, 126 },
+	};
+	size_t i;
+
+	for (i = 0; i < sizeof tests / sizeof *tests; i++) {
+		struct tm tm;
+		char *end;
+		ptrdiff_t off;
+
+		memset(&tm, 0, sizeof tm);
+		end = strptime(tests[i].input, tests[i].format, &tm);
+		off = end ? end - tests[i].input : -1;
+		if (off != tests[i].end)
+			t_error("strptime(\"%s\", \"%s\") %s, want %s\n",
+				tests[i].input, tests[i].format,
+				end ? "succeeded" : "failed",
+				tests[i].end < 0 ? "failure" : "success");
+		else if (end && tm.tm_year != tests[i].year)
+			t_error("strptime(\"%s\", \"%s\") gave tm_year %d, want %d\n",
+				tests[i].input, tests[i].format, tm.tm_year,
+				tests[i].year);
+	}
+	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.