|
|
Message-ID: <20260805141033.841558-2-matthias.goergens@gmail.com>
Date: Wed, 5 Aug 2026 22:10:24 +0800
From: Matthias Goergens <matthias.goergens@...il.com>
To: musl@...ts.openwall.com
Cc: Matthias Goergens <matthias.goergens@...il.com>
Subject: [PATCH 01/10] regression: test fseeko SEEK_CUR offset underflow
With unread buffered input, fseeko must reject a relative offset
whose buffer adjustment would overflow off_t, fail with EOVERFLOW
without calling the underlying seek or discarding the buffer, and
pass exact boundary offsets through unchanged.
Covered by the musl patch "stdio: avoid overflow adjusting
relative seek offset".
---
src/regression/fseeko-seek-cur-underflow.c | 113 +++++++++++++++++++++
1 file changed, 113 insertions(+)
create mode 100644 src/regression/fseeko-seek-cur-underflow.c
diff --git a/src/regression/fseeko-seek-cur-underflow.c b/src/regression/fseeko-seek-cur-underflow.c
new file mode 100644
index 0000000..c9fdab9
--- /dev/null
+++ b/src/regression/fseeko-seek-cur-underflow.c
@@ -0,0 +1,113 @@
+// fseeko must fail with EOVERFLOW when adjusting a relative SEEK_CUR
+// offset by the unread buffered input would overflow off_t.
+// musl subtracted the buffer length without checking, so a valid
+// LLONG_MIN offset wrapped and reached the underlying seek.
+#define _GNU_SOURCE
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include "test.h"
+
+struct state {
+ int read_done;
+ int seek_calls;
+ off_t seen_offset;
+};
+
+static ssize_t read_cookie(void *cookie, char *buf, size_t size)
+{
+ struct state *st = cookie;
+ if (st->read_done)
+ return 0;
+ st->read_done = 1;
+ if (size > 6)
+ size = 6;
+ memcpy(buf, "abcdef", size);
+ return size;
+}
+
+static int seek_cookie(void *cookie, off_t *off, int whence)
+{
+ struct state *st = cookie;
+ if (whence != SEEK_CUR)
+ return -1;
+ st->seek_calls++;
+ st->seen_offset = *off;
+ return 0;
+}
+
+static FILE *make_stream(struct state *st)
+{
+ cookie_io_functions_t io = {
+ .read = read_cookie,
+ .seek = seek_cookie,
+ };
+ FILE *f = fopencookie(st, "r", io);
+ if (f && fgetc(f) != 'a') {
+ fclose(f);
+ return 0;
+ }
+ return f;
+}
+
+int main(void)
+{
+ struct state st = {0};
+ FILE *f = make_stream(&st);
+ int r, c;
+
+ if (!f) {
+ t_error("fopencookie setup failed\n");
+ return t_status;
+ }
+
+ /* five bytes are buffered; LLONG_MIN - 5 is not representable */
+ errno = 0;
+ r = fseeko(f, LLONG_MIN, SEEK_CUR);
+ if (r != -1 || errno != EOVERFLOW)
+ t_error("fseeko(f, LLONG_MIN, SEEK_CUR) = %d (errno %d), want -1/EOVERFLOW\n",
+ r, errno);
+ if (st.seek_calls)
+ t_error("underlying seek was called for the overflowing offset\n");
+ c = fgetc(f);
+ if (c != 'b')
+ t_error("read buffer not preserved after failed seek: got %c, want b\n",
+ c >= 32 && c < 127 ? c : '?');
+ fclose(f);
+
+ /* boundary: LLONG_MIN + 5 must not take the overflow path; the
+ underlying seek must see exactly LLONG_MIN. musl reports a
+ successful seek to a negative absolute offset as -1 without
+ setting errno, so only the callback arguments are checked. */
+ st = (struct state){0};
+ f = make_stream(&st);
+ if (!f) {
+ t_error("fopencookie setup failed\n");
+ return t_status;
+ }
+ errno = 0;
+ r = fseeko(f, LLONG_MIN + 5, SEEK_CUR);
+ if (st.seek_calls != 1 || st.seen_offset != LLONG_MIN)
+ t_error("fseeko(f, LLONG_MIN+5, SEEK_CUR): seek calls %d, offset %lld; want 1, %lld\n",
+ st.seek_calls, (long long)st.seen_offset, (long long)LLONG_MIN);
+ if (r != -1 || errno != 0)
+ t_error("fseeko(f, LLONG_MIN+5, SEEK_CUR) = %d (errno %d), want -1 with errno unset\n",
+ r, errno);
+ fclose(f);
+
+ /* ordinary offset control: 10 with 5 buffered bytes seeks to 5 */
+ st = (struct state){0};
+ f = make_stream(&st);
+ if (!f) {
+ t_error("fopencookie setup failed\n");
+ return t_status;
+ }
+ r = fseeko(f, 10, SEEK_CUR);
+ if (r != 0 || st.seek_calls != 1 || st.seen_offset != 5)
+ t_error("fseeko(f, 10, SEEK_CUR) = %d, seek calls %d, offset %lld; want 0, 1, 5\n",
+ r, st.seek_calls, (long long)st.seen_offset);
+ fclose(f);
+
+ 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.