Bug 1174015: Keep the maxlen member of SprintfState under PR_INT32_MAX.
r=kaie.
--- a/pr/src/io/prprf.c
+++ b/pr/src/io/prprf.c
@@ -32,17 +32,17 @@
typedef struct SprintfStateStr SprintfState;
struct SprintfStateStr {
int (*stuff)(SprintfState *ss, const char *sp, PRUint32 len);
char *base;
char *cur;
- PRUint32 maxlen;
+ PRUint32 maxlen; /* Must not exceed PR_INT32_MAX. */
int (*func)(void *arg, const char *sp, PRUint32 len);
void *arg;
};
/*
** Numbered Argument
*/
@@ -1055,16 +1055,23 @@ static int dosprintf(SprintfState *ss, c
}
/************************************************************************/
static int FuncStuff(SprintfState *ss, const char *sp, PRUint32 len)
{
int rv;
+ /*
+ ** We will add len to ss->maxlen at the end of the function. First check
+ ** if ss->maxlen + len would overflow or be greater than PR_INT32_MAX.
+ */
+ if (PR_UINT32_MAX - ss->maxlen < len || ss->maxlen + len > PR_INT32_MAX) {
+ return -1;
+ }
rv = (*ss->func)(ss->arg, sp, len);
if (rv < 0) {
return rv;
}
ss->maxlen += len;
return 0;
}
@@ -1100,19 +1107,31 @@ PR_IMPLEMENT(PRUint32) PR_vsxprintf(PRSt
*/
static int GrowStuff(SprintfState *ss, const char *sp, PRUint32 len)
{
ptrdiff_t off;
char *newbase;
PRUint32 newlen;
off = ss->cur - ss->base;
+ if (PR_UINT32_MAX - len < off) {
+ /* off + len would be too big. */
+ return -1;
+ }
if (off + len >= ss->maxlen) {
/* Grow the buffer */
- newlen = ss->maxlen + ((len > 32) ? len : 32);
+ PRUint32 increment = (len > 32) ? len : 32;
+ if (PR_UINT32_MAX - ss->maxlen < increment) {
+ /* ss->maxlen + increment would overflow. */
+ return -1;
+ }
+ newlen = ss->maxlen + increment;
+ if (newlen > PR_INT32_MAX) {
+ return -1;
+ }
if (ss->base) {
newbase = (char*) PR_REALLOC(ss->base, newlen);
} else {
newbase = (char*) PR_MALLOC(newlen);
}
if (!newbase) {
/* Ran out of memory */
return -1;
@@ -1205,18 +1224,18 @@ PR_IMPLEMENT(PRUint32) PR_snprintf(char
}
PR_IMPLEMENT(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen,const char *fmt,
va_list ap)
{
SprintfState ss;
PRUint32 n;
- PR_ASSERT((PRInt32)outlen > 0);
- if ((PRInt32)outlen <= 0) {
+ PR_ASSERT(outlen != 0 && outlen <= PR_INT32_MAX);
+ if (outlen == 0 || outlen > PR_INT32_MAX) {
return 0;
}
ss.stuff = LimitStuff;
ss.base = out;
ss.cur = out;
ss.maxlen = outlen;
(void) dosprintf(&ss, fmt, ap);
@@ -1242,17 +1261,20 @@ PR_IMPLEMENT(char *) PR_sprintf_append(c
PR_IMPLEMENT(char *) PR_vsprintf_append(char *last, const char *fmt, va_list ap)
{
SprintfState ss;
int rv;
ss.stuff = GrowStuff;
if (last) {
- int lastlen = strlen(last);
+ size_t lastlen = strlen(last);
+ if (lastlen > PR_INT32_MAX) {
+ return 0;
+ }
ss.base = last;
ss.cur = last + lastlen;
ss.maxlen = lastlen;
} else {
ss.base = 0;
ss.cur = 0;
ss.maxlen = 0;
}