Bug 678362 - HashTable should not require callers to bounds-check initial capacity (r=waldo)

--HG--
extra : rebase_source : d0bb0faa097cd04b5be0644f17a37fb96aaffc2d
This commit is contained in:
Luke Wagner 2011-08-11 18:10:16 -07:00
parent 82d1f93fca
commit 82b532273f
3 changed files with 41 additions and 7 deletions

View File

@ -298,7 +298,8 @@ class HashTable : private AllocPolicy
static const unsigned sMinSizeLog2 = 4;
static const unsigned sMinSize = 1 << sMinSizeLog2;
static const unsigned sSizeLimit = JS_BIT(24);
static const unsigned sMaxInit = JS_BIT(23);
static const unsigned sMaxCapacity = JS_BIT(24);
static const unsigned sHashBits = tl::BitSize<HashNumber>::result;
static const uint8 sMinAlphaFrac = 64; /* (0x100 * .25) taken from jsdhash.h */
static const uint8 sMaxAlphaFrac = 192; /* (0x100 * .75) taken from jsdhash.h */
@ -308,6 +309,14 @@ class HashTable : private AllocPolicy
static const HashNumber sRemovedKey = Entry::sRemovedKey;
static const HashNumber sCollisionBit = Entry::sCollisionBit;
static void staticAsserts()
{
/* Rely on compiler "constant overflow warnings". */
JS_STATIC_ASSERT(((sMaxInit * sInvMaxAlpha) >> 7) < sMaxCapacity);
JS_STATIC_ASSERT((sMaxCapacity * sInvMaxAlpha) <= UINT32_MAX);
JS_STATIC_ASSERT((sMaxCapacity * sizeof(Entry)) <= UINT32_MAX);
}
static bool isLiveHash(HashNumber hash)
{
return Entry::isLiveHash(hash);
@ -365,7 +374,10 @@ class HashTable : private AllocPolicy
* Correct for sMaxAlphaFrac such that the table will not resize
* when adding 'length' entries.
*/
JS_ASSERT(length < (uint32(1) << 23));
if (length > sMaxInit) {
this->reportAllocOverflow();
return false;
}
uint32 capacity = (length * sInvMaxAlpha) >> 7;
if (capacity < sMinSize)
@ -379,10 +391,7 @@ class HashTable : private AllocPolicy
}
capacity = roundUp;
if (capacity >= sSizeLimit) {
this->reportAllocOverflow();
return false;
}
JS_ASSERT(capacity <= sMaxCapacity);
table = createTable(*this, capacity);
if (!table)
@ -536,7 +545,7 @@ class HashTable : private AllocPolicy
uint32 oldCap = tableCapacity;
uint32 newLog2 = sHashBits - hashShift + deltaLog2;
uint32 newCapacity = JS_BIT(newLog2);
if (newCapacity >= sSizeLimit) {
if (newCapacity > sMaxCapacity) {
this->reportAllocOverflow();
return false;
}

View File

@ -0,0 +1,24 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var r1 = [0, 1, 2, 3];
Object.defineProperty(r1, (1 << 23) - 1, {});
JSON.stringify({ 0: 0, 1: 1, 2: 2, 3: 3 }, r1)
var r2 = [0, 1, 2, 3];
Object.defineProperty(r2, (1 << 30), {});
try
{
JSON.stringify({ 0: 0, 1: 1, 2: 2, 3: 3 }, r2)
}
catch (e)
{
assertEq(""+e, "InternalError: allocation size overflow");
}
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

View File

@ -16,6 +16,7 @@ script extension-methods-reject-null-undefined-this.js
skip-if(!xulRuntime.shell) script function-definition-with.js # needs evaluate()
script function-properties.js
script iterator-in-catch.js
script JSON-string-replacer-overflow.js
skip-if(!xulRuntime.shell) script legacy-JSON.js # needs parseLegacyJSON
fails script nested-delete-name-in-evalcode.js # bug 604301, at a minimum
script proxy-strict.js