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-3-matthias.goergens@gmail.com>
Date: Wed,  5 Aug 2026 22:10:25 +0800
From: Matthias Goergens <matthias.goergens@...il.com>
To: musl@...ts.openwall.com
Cc: Matthias Goergens <matthias.goergens@...il.com>
Subject: [PATCH 02/10] regression: test ftello overflow with buffered output

ftello must fail with EOVERFLOW when pending buffered output does
not fit on top of the underlying file position, keep the buffer
unflushed, and still report the exact LLONG_MAX boundary.

Covered by the musl patch "stdio: report overflow in buffered
stream position".
---
 src/regression/ftello-buffered-overflow.c | 115 ++++++++++++++++++++++
 1 file changed, 115 insertions(+)
 create mode 100644 src/regression/ftello-buffered-overflow.c

diff --git a/src/regression/ftello-buffered-overflow.c b/src/regression/ftello-buffered-overflow.c
new file mode 100644
index 0000000..087aa9e
--- /dev/null
+++ b/src/regression/ftello-buffered-overflow.c
@@ -0,0 +1,115 @@
+// ftello must fail with EOVERFLOW when the pending buffered output
+// does not fit in off_t on top of the underlying file position.
+// musl added the buffer length without checking, so a position near
+// LLONG_MAX wrapped to an apparently successful negative result.
+#define _GNU_SOURCE
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include "test.h"
+
+struct state {
+	off_t pos;
+	int write_calls;
+};
+
+static ssize_t write_cookie(void *cookie, const char *buf, size_t len)
+{
+	struct state *st = cookie;
+	(void)buf;
+	st->write_calls++;
+	return len;
+}
+
+static int seek_cookie(void *cookie, off_t *off, int whence)
+{
+	struct state *st = cookie;
+	if ((whence != SEEK_CUR && whence != SEEK_END) || *off)
+		return -1;
+	*off = st->pos;
+	return 0;
+}
+
+static FILE *make_stream(struct state *st)
+{
+	cookie_io_functions_t io = {
+		.write = write_cookie,
+		.seek = seek_cookie,
+	};
+	return fopencookie(st, "w", io);
+}
+
+static void check_overflow(void)
+{
+	struct state st = { .pos = LLONG_MAX };
+	FILE *f = make_stream(&st);
+	off_t off;
+
+	if (!f || fputc('x', f) == EOF) {
+		t_error("setup failed\n");
+		return;
+	}
+	/* LLONG_MAX + 1 buffered byte cannot be represented */
+	errno = 0;
+	off = ftello(f);
+	if (off != -1 || errno != EOVERFLOW)
+		t_error("ftello at LLONG_MAX with 1 buffered byte = %lld (errno %d), want -1/EOVERFLOW\n",
+			(long long)off, errno);
+	if (st.write_calls)
+		t_error("stream was flushed by the failing ftello\n");
+
+	/* the pending byte must remain buffered and recoverable */
+	st.pos = 10;
+	errno = 0;
+	off = ftello(f);
+	if (off != 11 || st.write_calls)
+		t_error("ftello after repositioning = %lld (write calls %d), want 11, 0\n",
+			(long long)off, st.write_calls);
+	fclose(f);
+}
+
+static void check_fgetpos(void)
+{
+	struct state st = { .pos = LLONG_MAX };
+	FILE *f = make_stream(&st);
+	fpos_t pos;
+
+	if (!f || fputc('x', f) == EOF) {
+		t_error("setup failed\n");
+		return;
+	}
+	errno = 0;
+	if (fgetpos(f, &pos) != -1 || errno != EOVERFLOW)
+		t_error("fgetpos at LLONG_MAX with 1 buffered byte did not fail with EOVERFLOW (errno %d)\n",
+			errno);
+	if (st.write_calls)
+		t_error("stream was flushed by the failing fgetpos\n");
+	fclose(f);
+}
+
+static void check_boundary(void)
+{
+	struct state st = { .pos = LLONG_MAX - 1 };
+	FILE *f = make_stream(&st);
+	off_t off;
+
+	if (!f || fputc('x', f) == EOF) {
+		t_error("setup failed\n");
+		return;
+	}
+	/* exact upper boundary: (LLONG_MAX - 1) + 1 == LLONG_MAX */
+	errno = 0;
+	off = ftello(f);
+	if (off != LLONG_MAX)
+		t_error("ftello at LLONG_MAX-1 with 1 buffered byte = %lld (errno %d), want %lld\n",
+			(long long)off, errno, (long long)LLONG_MAX);
+	fclose(f);
+}
+
+int main(void)
+{
+	check_overflow();
+	check_fgetpos();
+	check_boundary();
+	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.