diff --git a/js/src/ds/LifoAlloc.cpp b/js/src/ds/LifoAlloc.cpp index 3f63bb78906..872c2172fb7 100644 --- a/js/src/ds/LifoAlloc.cpp +++ b/js/src/ds/LifoAlloc.cpp @@ -65,6 +65,30 @@ BumpChunk::new_(size_t chunkSize) return result; } +void +BumpChunk::delete_(BumpChunk *chunk) +{ +#ifdef DEBUG + memset(chunk, 0xcd, sizeof(*chunk) + chunk->bumpSpaceSize); +#endif + js_free(chunk); +} + +bool +BumpChunk::canAlloc(size_t n) +{ + char *aligned = AlignPtr(bump); + char *bumped = aligned + n; + return bumped <= limit && bumped > headerBase(); +} + +bool +BumpChunk::canAllocUnaligned(size_t n) +{ + char *bumped = bump + n; + return bumped <= limit && bumped > headerBase(); +} + void * BumpChunk::tryAllocUnaligned(size_t n) { @@ -73,6 +97,7 @@ BumpChunk::tryAllocUnaligned(size_t n) if (newBump > limit) return NULL; + JS_ASSERT(canAllocUnaligned(n)); setBump(newBump); return oldBump; } @@ -136,9 +161,20 @@ LifoAlloc::getOrCreateChunk(size_t n) } size_t defaultChunkFreeSpace = defaultChunkSize_ - sizeof(BumpChunk); - size_t chunkSize = n > defaultChunkFreeSpace - ? RoundUpPow2(n + sizeof(BumpChunk)) - : defaultChunkSize_; + size_t chunkSize; + if (n > defaultChunkFreeSpace) { + size_t allocSizeWithHeader = n + sizeof(BumpChunk); + + /* Guard for overflow. */ + if (allocSizeWithHeader < n || + (allocSizeWithHeader & (size_t(1) << (tl::BitSize::result - 1)))) { + return NULL; + } + + chunkSize = RoundUpPow2(allocSizeWithHeader); + } else { + chunkSize = defaultChunkSize_; + } /* If we get here, we couldn't find an existing BumpChunk to fill the request. */ BumpChunk *newChunk = BumpChunk::new_(chunkSize); diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index bff07bad37e..0fa9388a458 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -79,7 +79,8 @@ class BumpChunk BumpChunk *next_; size_t bumpSpaceSize; - char *base() const { return limit - bumpSpaceSize; } + char *headerBase() { return reinterpret_cast(this); } + char *bumpBase() const { return limit - bumpSpaceSize; } BumpChunk *thisDuringConstruction() { return this; } @@ -98,7 +99,7 @@ class BumpChunk } void setBump(void *ptr) { - JS_ASSERT(base() <= ptr); + JS_ASSERT(bumpBase() <= ptr); JS_ASSERT(ptr <= limit); DebugOnly prevBump = bump; bump = static_cast(ptr); @@ -110,10 +111,10 @@ class BumpChunk BumpChunk *next() const { return next_; } void setNext(BumpChunk *succ) { next_ = succ; } - size_t used() const { return bump - base(); } + size_t used() const { return bump - bumpBase(); } void resetBump() { - setBump(reinterpret_cast(this) + sizeof(BumpChunk)); + setBump(headerBase() + sizeof(BumpChunk)); } void *mark() const { return bump; } @@ -125,25 +126,26 @@ class BumpChunk } bool contains(void *mark) const { - return base() <= mark && mark <= limit; + return bumpBase() <= mark && mark <= limit; } - bool canAlloc(size_t n) { - return AlignPtr(bump) + n <= limit; - } - - bool canAllocUnaligned(size_t n) { - return bump + n <= limit; - } + bool canAlloc(size_t n); + bool canAllocUnaligned(size_t n); /* Try to perform an allocation of size |n|, return null if not possible. */ JS_ALWAYS_INLINE void *tryAlloc(size_t n) { char *aligned = AlignPtr(bump); char *newBump = aligned + n; + if (newBump > limit) return NULL; + /* Check for overflow. */ + if (JS_UNLIKELY(newBump < bump)) + return NULL; + + JS_ASSERT(canAlloc(n)); /* Ensure consistency between "can" and "try". */ setBump(newBump); return aligned; } @@ -157,13 +159,7 @@ class BumpChunk } static BumpChunk *new_(size_t chunkSize); - - static void delete_(BumpChunk *chunk) { -#ifdef DEBUG - memset(chunk, 0xcd, sizeof(*chunk) + chunk->bumpSpaceSize); -#endif - js_free(chunk); - } + static void delete_(BumpChunk *chunk); }; } /* namespace detail */