Bug 690933: Guard on LifoAlloc overflow. (r=luke)

This commit is contained in:
Chris Leary 2011-10-11 09:42:26 -07:00
parent 685049419b
commit f4c00c0c84
2 changed files with 54 additions and 22 deletions

View File

@ -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<size_t>::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);

View File

@ -79,7 +79,8 @@ class BumpChunk
BumpChunk *next_;
size_t bumpSpaceSize;
char *base() const { return limit - bumpSpaceSize; }
char *headerBase() { return reinterpret_cast<char *>(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<char *> prevBump = bump;
bump = static_cast<char *>(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<char *>(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 */