Skip to content

Commit ed93fc3

Browse files
committed
Fix fread() with 2gb+ sizes
1 parent 5f61d27 commit ed93fc3

File tree

8 files changed

+253
-118
lines changed

8 files changed

+253
-118
lines changed

libc/calls/struct/iovec.internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include "libc/mem/alloca.h"
66
COSMOPOLITAN_C_START_
77

8-
ssize_t __robust_writev(int, struct iovec *, int);
98
int64_t sys_preadv(int, struct iovec *, int, int64_t, int64_t);
109
int64_t sys_pwritev(int, const struct iovec *, int, int64_t, int64_t);
1110
int64_t sys_readv(int32_t, const struct iovec *, int32_t);

libc/calls/writevuninterruptible.c

Lines changed: 0 additions & 45 deletions
This file was deleted.

libc/stdio/fread_unlocked.c

Lines changed: 89 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/assert.h"
1920
#include "libc/calls/calls.h"
2021
#include "libc/calls/struct/iovec.h"
2122
#include "libc/errno.h"
@@ -25,6 +26,41 @@
2526
#include "libc/stdio/stdio.h"
2627
#include "libc/str/str.h"
2728
#include "libc/sysv/consts/o.h"
29+
#include "libc/sysv/errfuns.h"
30+
31+
static ssize_t readvall(int fd, struct iovec *iov, int iovlen) {
32+
int olde;
33+
ssize_t rc;
34+
size_t got, toto;
35+
toto = 0;
36+
olde = errno;
37+
do {
38+
if ((rc = readv(fd, iov, iovlen)) == -1) {
39+
if (toto && errno == EINTR) {
40+
errno = olde;
41+
continue;
42+
}
43+
return -1;
44+
}
45+
got = rc;
46+
toto += got;
47+
for (;;) {
48+
if (!iov->iov_len) {
49+
--iovlen;
50+
++iov;
51+
} else if (got >= iov->iov_len) {
52+
got -= iov->iov_len;
53+
--iovlen;
54+
++iov;
55+
} else {
56+
iov->iov_base += got;
57+
iov->iov_len -= got;
58+
break;
59+
}
60+
}
61+
} while (got && iovlen);
62+
return toto;
63+
}
2864

2965
/**
3066
* Reads data from stream.
@@ -36,11 +72,10 @@
3672
size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) {
3773
char *p;
3874
ssize_t rc;
39-
size_t n, m;
4075
struct iovec iov[2];
41-
if (!stride) {
42-
return 0;
43-
}
76+
size_t n, m, got, need;
77+
78+
// check state and parameters
4479
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
4580
f->state = errno = EBADF;
4681
return 0;
@@ -53,52 +88,74 @@ size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) {
5388
f->state = errno = EOVERFLOW;
5489
return 0;
5590
}
91+
if (!n)
92+
return 0;
93+
94+
// try to fulfill request from buffer if possible
5695
p = buf;
5796
m = f->end - f->beg;
58-
if (MIN(n, m)) {
59-
memcpy(p, f->buf + f->beg, MIN(n, m));
60-
}
61-
if (n < m) {
62-
f->beg += n;
63-
return count;
64-
}
65-
if (n == m) {
66-
f->beg = f->end = 0;
97+
if (n <= m) {
98+
memcpy(p, f->buf + f->beg, n);
99+
if ((f->beg += n) == f->end) {
100+
f->beg = 0;
101+
f->end = 0;
102+
}
67103
return count;
68104
}
105+
106+
// handle end-of-file condition in fileless mode
69107
if (f->fd == -1) {
70-
f->beg = 0;
71-
f->end = 0;
72-
f->state = -1;
108+
m /= stride;
109+
m *= stride;
110+
if (m)
111+
memcpy(p, f->buf + f->beg, m);
112+
if ((f->beg += m) == f->end) {
113+
f->state = EOF;
114+
f->beg = 0;
115+
f->end = 0;
116+
}
73117
return m / stride;
74118
}
119+
120+
// `n` is number of bytes requested by caller
121+
// `m` is how much of `n` came from existing buffer
122+
// `iov[0]` reads remainder of the caller request
123+
// `iov[1]` reads ahead extra content into buffer
124+
if (m)
125+
memcpy(p, f->buf + f->beg, m);
75126
iov[0].iov_base = p + m;
76-
iov[0].iov_len = n - m;
127+
iov[0].iov_len = need = n - m;
77128
if (f->bufmode != _IONBF && n < f->size) {
78129
iov[1].iov_base = f->buf;
79-
if (f->size > PUSHBACK) {
130+
if (f->size > PUSHBACK)
80131
iov[1].iov_len = f->size - PUSHBACK;
81-
} else {
132+
else
82133
iov[1].iov_len = f->size;
83-
}
84134
} else {
85135
iov[1].iov_base = NULL;
86136
iov[1].iov_len = 0;
87137
}
88-
if ((rc = readv(f->fd, iov, 2)) == -1) {
138+
if ((rc = readvall(f->fd, iov, 2)) == -1) {
89139
f->state = errno;
90140
return 0;
91141
}
92-
n = rc;
93-
f->beg = 0;
94-
f->end = 0;
95-
if (n > iov[0].iov_len) {
96-
f->end += n - iov[0].iov_len;
97-
return count;
98-
} else {
99-
n = (m + n) / stride;
100-
if (n < count)
101-
f->state = -1;
102-
return n;
142+
got = rc;
143+
144+
// handle partial fulfillment
145+
if (got < need) {
146+
got += m;
147+
if (got % stride) {
148+
f->state = eio();
149+
return 0;
150+
}
151+
f->beg = 0;
152+
f->end = 0;
153+
f->state = EOF;
154+
return got / stride;
103155
}
156+
157+
// handle overfulfillment
158+
f->beg = 0;
159+
f->end = got - need;
160+
return count;
104161
}

libc/stdio/fwrite_unlocked.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,40 @@
2727
#include "libc/str/str.h"
2828
#include "libc/sysv/consts/o.h"
2929

30+
static ssize_t writevall(int fd, struct iovec *iov, int iovlen) {
31+
int olde;
32+
ssize_t rc;
33+
size_t got, toto;
34+
toto = 0;
35+
olde = errno;
36+
do {
37+
if ((rc = writev(fd, iov, iovlen)) == -1) {
38+
if (toto && errno == EINTR) {
39+
errno = olde;
40+
continue;
41+
}
42+
return -1;
43+
}
44+
got = rc;
45+
toto += got;
46+
for (;;) {
47+
if (!iov->iov_len) {
48+
--iovlen;
49+
++iov;
50+
} else if (got >= iov->iov_len) {
51+
got -= iov->iov_len;
52+
--iovlen;
53+
++iov;
54+
} else {
55+
iov->iov_base += got;
56+
iov->iov_len -= got;
57+
break;
58+
}
59+
}
60+
} while (got && iovlen);
61+
return toto;
62+
}
63+
3064
/**
3165
* Writes data to stream.
3266
*
@@ -104,7 +138,7 @@ size_t fwrite_unlocked(const void *data, size_t stride, size_t count, FILE *f) {
104138
iov[1].iov_base = (void *)data;
105139
iov[1].iov_len = n;
106140
n += f->beg;
107-
if (__robust_writev(f->fd, iov, 2) == -1) {
141+
if ((rc = writevall(f->fd, iov, 2)) == -1) {
108142
f->state = errno;
109143
return 0;
110144
}

libc/stdio/vdprintf.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19-
#include "libc/calls/struct/iovec.internal.h"
19+
#include "libc/calls/struct/iovec.h"
2020
#include "libc/dce.h"
2121
#include "libc/fmt/internal.h"
2222
#include "libc/limits.h"
@@ -42,7 +42,7 @@ static int vdprintf_putc(const char *s, struct VdprintfState *t, size_t n) {
4242
iov[0].iov_len = t->n;
4343
iov[1].iov_base = (void *)s;
4444
iov[1].iov_len = n;
45-
if (__robust_writev(t->fd, iov, 2) == -1) {
45+
if (writev(t->fd, iov, 2) == -1) {
4646
return -1;
4747
}
4848
t->t += t->n;
@@ -68,7 +68,7 @@ int vdprintf(int fd, const char *fmt, va_list va) {
6868
if (t.n) {
6969
iov[0].iov_base = t.b;
7070
iov[0].iov_len = t.n;
71-
if (__robust_writev(t.fd, iov, 1) == -1) {
71+
if (writev(t.fd, iov, 1) == -1) {
7272
return -1;
7373
}
7474
t.t += t.n;

0 commit comments

Comments
 (0)