X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fstdio%2Fgetdelim.c;h=df114441c72562a8bfd39e6e1fb3f4687d6715e9;hb=36b72cd6fdfed2cac6b6ff1ed58a96d8265785cf;hp=c313775d3d026f11a9660e21b888959ea35f680a;hpb=849e7603e9004fd292a93df64dd3524025f2987a;p=musl diff --git a/src/stdio/getdelim.c b/src/stdio/getdelim.c index c313775d..df114441 100644 --- a/src/stdio/getdelim.c +++ b/src/stdio/getdelim.c @@ -32,22 +32,34 @@ ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restric z = 0; k = 0; } - if (i+k+1 >= *n) { - if (k >= SIZE_MAX/2-i) goto oom; + 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; } - memcpy(*s+i, f->rpos, k); - f->rpos += k; - i += k; + if (k) { + memcpy(*s+i, f->rpos, k); + f->rpos += k; + i += k; + } if (z) break; if ((c = getc_unlocked(f)) == EOF) { if (!i || !feof(f)) { @@ -56,19 +68,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->mode |= f->mode-1; - f->flags |= F_ERR; - FUNLOCK(f); - errno = ENOMEM; - return -1; } weak_alias(getdelim, __getdelim);