Blob Blame History Raw
diff --git a/lib/ds/plarena.c b/lib/ds/plarena.c
--- a/lib/ds/plarena.c
+++ b/lib/ds/plarena.c
@@ -88,16 +88,19 @@ PR_IMPLEMENT(void) PL_InitArenaPool(
         align = PL_ARENA_DEFAULT_ALIGN;
 
     if (align < sizeof(pmasks)/sizeof(pmasks[0]))
         pool->mask = pmasks[align];
     else
         pool->mask = PR_BITMASK(PR_CeilingLog2(align));
 
     pool->first.next = NULL;
+    /* Set all three addresses in pool->first to the same dummy value.
+     * These addresses are only compared with each other, but never
+     * dereferenced. */
     pool->first.base = pool->first.avail = pool->first.limit =
         (PRUword)PL_ARENA_ALIGN(pool, &pool->first + 1);
     pool->current = &pool->first;
     /*
      * Compute the net size so that each arena's gross size is |size|.
      * sizeof(PLArena) + pool->mask is the header and alignment slop
      * that PL_ArenaAllocate adds to the net size.
      */
@@ -139,20 +142,24 @@ PR_IMPLEMENT(void) PL_InitArenaPool(
 ** See also: bugzilla: 45343.
 **
 */
 
 PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb)
 {
     PLArena *a;   
     char *rp;     /* returned pointer */
+    PRUint32 nbOld;
 
     PR_ASSERT((nb & pool->mask) == 0);
     
+    nbOld = nb;
     nb = (PRUword)PL_ARENA_ALIGN(pool, nb); /* force alignment */
+    if (nb < nbOld)
+        return NULL;
 
     /* attempt to allocate from arenas at pool->current */
     {
         a = pool->current;
         do {
             if ( nb <= a->limit - a->avail )  {
                 pool->current = a;
                 rp = (char *)a->avail;
@@ -203,16 +210,17 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PL
             a = (PLArena*)PR_MALLOC(sz);
         }
         if ( NULL != a )  {
             a->limit = (PRUword)a + sz;
             a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1);
             PL_MAKE_MEM_NOACCESS((void*)a->avail, a->limit - a->avail);
             rp = (char *)a->avail;
             a->avail += nb;
+            PR_ASSERT(a->avail <= a->limit);
             /* the newly allocated arena is linked after pool->current 
             *  and becomes pool->current */
             a->next = pool->current->next;
             pool->current->next = a;
             pool->current = a;
             if ( NULL == pool->first.next )
                 pool->first.next = a;
             PL_COUNT_ARENA(pool,++);
@@ -225,16 +233,18 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PL
     return(NULL);
 } /* --- end PL_ArenaAllocate() --- */
 
 PR_IMPLEMENT(void *) PL_ArenaGrow(
     PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr)
 {
     void *newp;
 
+    if (PR_UINT32_MAX - size < incr)
+        return NULL;
     PL_ARENA_ALLOCATE(newp, pool, size + incr);
     if (newp)
         memcpy(newp, p, size);
     return newp;
 }
 
 static void ClearArenaList(PLArena *a, PRInt32 pattern)
 {
diff --git a/lib/ds/plarena.h b/lib/ds/plarena.h
--- a/lib/ds/plarena.h
+++ b/lib/ds/plarena.h
@@ -132,44 +132,49 @@ void __asan_unpoison_memory_region(void 
         PL_InitArenaPool(pool, name, size, PL_ARENA_CONST_ALIGN_MASK + 1)
 #else
 #define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + (pool)->mask) & ~(pool)->mask)
 #endif
 
 #define PL_ARENA_ALLOCATE(p, pool, nb) \
     PR_BEGIN_MACRO \
         PLArena *_a = (pool)->current; \
-        PRUint32 _nb = PL_ARENA_ALIGN(pool, nb); \
+        PRUint32 _nb = PL_ARENA_ALIGN(pool, (PRUint32)nb); \
         PRUword _p = _a->avail; \
-        PRUword _q = _p + _nb; \
-        if (_q > _a->limit) { \
+        if (_nb < (PRUint32)nb) { \
+            _p = 0; \
+        } else if (_nb > (_a->limit - _a->avail)) { \
             _p = (PRUword)PL_ArenaAllocate(pool, _nb); \
         } else { \
-            _a->avail = _q; \
+            _a->avail += _nb; \
         } \
         p = (void *)_p; \
-        PL_MAKE_MEM_UNDEFINED(p, nb); \
-        PL_ArenaCountAllocation(pool, nb); \
+        if (p) { \
+            PL_MAKE_MEM_UNDEFINED(p, (PRUint32)nb); \
+            PL_ArenaCountAllocation(pool, (PRUint32)nb); \
+        } \
     PR_END_MACRO
 
 #define PL_ARENA_GROW(p, pool, size, incr) \
     PR_BEGIN_MACRO \
         PLArena *_a = (pool)->current; \
-        PRUint32 _incr = PL_ARENA_ALIGN(pool, incr); \
-        PRUword _p = _a->avail; \
-        PRUword _q = _p + _incr; \
-        if (_p == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \
-            _q <= _a->limit) { \
-            PL_MAKE_MEM_UNDEFINED((unsigned char *)(p) + size, incr); \
-            _a->avail = _q; \
-            PL_ArenaCountInplaceGrowth(pool, size, incr); \
+        PRUint32 _incr = PL_ARENA_ALIGN(pool, (PRUint32)incr); \
+        if (_incr < (PRUint32)incr) { \
+            p = NULL; \
+        } else if (_a->avail == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \
+            _incr <= (_a->limit - _a->avail)) { \
+            PL_MAKE_MEM_UNDEFINED((unsigned char *)(p) + size, (PRUint32)incr); \
+            _a->avail += _incr; \
+            PL_ArenaCountInplaceGrowth(pool, size, (PRUint32)incr); \
         } else { \
-            p = PL_ArenaGrow(pool, p, size, incr); \
+            p = PL_ArenaGrow(pool, p, size, (PRUint32)incr); \
         } \
-        PL_ArenaCountGrowth(pool, size, incr); \
+        if (p) {\
+            PL_ArenaCountGrowth(pool, size, (PRUint32)incr); \
+        } \
     PR_END_MACRO
 
 #define PL_ARENA_MARK(pool) ((void *) (pool)->current->avail)
 #define PR_UPTRDIFF(p,q) ((PRUword)(p) - (PRUword)(q))
 
 #define PL_CLEAR_UNUSED_PATTERN(a, pattern) \
     PR_BEGIN_MACRO \
         PR_ASSERT((a)->avail <= (a)->limit); \