diff options
Diffstat (limited to 'src/stdio/vsnprintf.c')
| -rw-r--r-- | src/stdio/vsnprintf.c | 42 | 
1 files changed, 23 insertions, 19 deletions
diff --git a/src/stdio/vsnprintf.c b/src/stdio/vsnprintf.c index 1f316ca4..ba17bd7d 100644 --- a/src/stdio/vsnprintf.c +++ b/src/stdio/vsnprintf.c @@ -2,33 +2,37 @@  static size_t sn_write(FILE *f, const unsigned char *s, size_t l)  { -	/* pretend to succeed, but discard data */ +	size_t k = f->wend - f->wpos; +	if (k > l) k = l; +	memcpy(f->wpos, s, k); +	f->wpos += k; +	/* pretend to succeed, but discard extra data */  	return l;  }  int vsnprintf(char *s, size_t n, const char *fmt, va_list ap)  {  	int r; -	FILE f; -	unsigned char buf[1]; +	char b; +	FILE f = { .lbf = EOF, .write = sn_write, .lock = -1 }; -	memset(&f, 0, sizeof(FILE)); -	f.lbf = EOF; -	f.write = sn_write; -	f.buf_size = 1; -	f.buf = buf; -	f.lock = -1; -	if (n > INT_MAX) { -		errno = EOVERFLOW; -		return -1; -	} else if (n > 0) { -		if (n > (char *)0+SIZE_MAX-s) n = (char *)0+SIZE_MAX-s; -		f.wpos = (void *)s; -		f.wbase = f.wend = (void *)(s+n-1); -		f.wstop = f.wend - 1; +	if (n-1 > INT_MAX-1) { +		if (n) { +			errno = EOVERFLOW; +			return -1; +		} +		s = &b; +		n = 1;  	} + +	/* Ensure pointers don't wrap if "infinite" n is passed in */ +	if (n > (char *)0+SIZE_MAX-s-1) n = (char *)0+SIZE_MAX-s-1; +	f.buf_size = n; +	f.buf = f.wpos = (void *)s; +	f.wbase = f.wend = (void *)(s+n);  	r = vfprintf(&f, fmt, ap); -	/* wpos points just after last byte written, or to s+n-1 (wbase) */ -	*f.wpos = 0; + +	/* Null-terminate, overwriting last char if dest buffer is full */ +	if (n) f.wpos[-(f.wpos == f.wend)] = 0;  	return r;  }  | 
