summaryrefslogtreecommitdiffstats
path: root/newlib/libc/stdio/fvwrite.c
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/stdio/fvwrite.c')
-rw-r--r--newlib/libc/stdio/fvwrite.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/newlib/libc/stdio/fvwrite.c b/newlib/libc/stdio/fvwrite.c
index 1cb6e0d1e..ef461d31d 100644
--- a/newlib/libc/stdio/fvwrite.c
+++ b/newlib/libc/stdio/fvwrite.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1990, 2006 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
@@ -127,13 +127,23 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio),
w = fp->_w;
if (fp->_flags & __SSTR)
{
- if (len > w && fp->_flags & __SMBF)
+ if (len >= w && fp->_flags & __SMBF)
{ /* must be asprintf family */
unsigned char *ptr;
int curpos = (fp->_p - fp->_bf._base);
+ /* Choose a geometric growth factor to avoid
+ quadratic realloc behavior, but use a rate less
+ than (1+sqrt(5))/2 to accomodate malloc
+ overhead. asprintf EXPECTS us to overallocate, so
+ that it can add a trailing \0 without
+ reallocating. The new allocation should thus be
+ max(prev_size*1.5, curpos+len+1). */
+ int newsize = fp->_bf._size * 3 / 2;
+ if (newsize < curpos + len + 1)
+ newsize = curpos + len + 1;
ptr = (unsigned char *)_realloc_r (_REENT,
fp->_bf._base,
- curpos + len);
+ newsize);
if (!ptr)
{
/* Free buffer which is no longer used. */
@@ -142,8 +152,9 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio),
}
fp->_bf._base = ptr;
fp->_p = ptr + curpos;
- fp->_bf._size = curpos + len;
- w = fp->_w = len;
+ fp->_bf._size = newsize;
+ w = len;
+ fp->_w = newsize - curpos;
}
if (len < w)
w = len;