X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fstdio%2Fgetdelim.c;h=d2f5b15ab1d7da3d693bcf5d9d4652ec89d4e858;hb=1f6cbdb434114139081fe65a9bafe775e9ab6c41;hp=d4b238828e2a973b970f184118f962a984113518;hpb=aaa29c26eed4a09625e61c6af31d16b1a4163fc3;p=musl diff --git a/src/stdio/getdelim.c b/src/stdio/getdelim.c index d4b23882..d2f5b15a 100644 --- a/src/stdio/getdelim.c +++ b/src/stdio/getdelim.c @@ -1,5 +1,6 @@ #include "stdio_impl.h" #include +#include #include #include @@ -14,6 +15,7 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric FLOCK(f); if (!n || !s) { + f->mode |= f->mode-1; f->flags |= F_ERR; FUNLOCK(f); errno = EINVAL; @@ -23,17 +25,32 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric if (!*s) *n=0; for (;;) { - z = memchr(f->rpos, delim, f->rend - f->rpos); - k = z ? z - f->rpos + 1 : f->rend - f->rpos; - if (i+k+1 >= *n) { - if (k >= SIZE_MAX/2-i) goto oom; + if (f->rpos != f->rend) { + z = memchr(f->rpos, delim, f->rend - f->rpos); + k = z ? z - f->rpos + 1 : f->rend - f->rpos; + } else { + z = 0; + k = 0; + } + if (i+k >= *n) { size_t m = i+k+2; if (!z && m < SIZE_MAX/4) m += m/2; tmp = realloc(*s, m); if (!tmp) { m = i+k+2; tmp = realloc(*s, m); - if (!tmp) goto oom; + if (!tmp) { + /* Copy as much as fits and ensure no + * pushback remains in the FILE buf. */ + k = *n-i; + memcpy(*s+i, f->rpos, k); + f->rpos += k; + f->mode |= f->mode-1; + f->flags |= F_ERR; + FUNLOCK(f); + errno = ENOMEM; + return -1; + } } *s = tmp; *n = m; @@ -49,18 +66,16 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric } break; } - if (((*s)[i++] = c) == delim) break; + /* If the byte read by getc won't fit without growing the + * output buffer, push it back for next iteration. */ + if (i+1 >= *n) *--f->rpos = c; + else if (((*s)[i++] = c) == delim) break; } (*s)[i] = 0; FUNLOCK(f); return i; -oom: - f->flags |= F_ERR; - FUNLOCK(f); - errno = ENOMEM; - return -1; } weak_alias(getdelim, __getdelim);