Bug 615147. r=dbaron a=blocking2.0:final

This commit is contained in:
Mats Palmgren 2011-01-14 01:22:26 +01:00
parent 2534080c69
commit 516b303803
3 changed files with 108 additions and 12 deletions

View File

@ -201,6 +201,9 @@ nsStringBuffer*
nsStringBuffer::Alloc(size_t size)
{
NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(PRUint32(-1)) &&
sizeof(nsStringBuffer) + size > size,
"mStorageSize will truncate");
nsStringBuffer *hdr =
(nsStringBuffer *) malloc(sizeof(nsStringBuffer) + size);
@ -221,12 +224,15 @@ nsStringBuffer::Realloc(nsStringBuffer* hdr, size_t size)
STRING_STAT_INCREMENT(Realloc);
NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
NS_ASSERTION(sizeof(nsStringBuffer) + size <= size_t(PRUint32(-1)) &&
sizeof(nsStringBuffer) + size > size,
"mStorageSize will truncate");
// no point in trying to save ourselves if we hit this assertion
NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string");
// Treat this as a release and addref for refcounting purposes, since we
// just asserted that the refcound is 1. If we don't do that, refcount
// just asserted that the refcount is 1. If we don't do that, refcount
// logging will claim we've leaked all sorts of stuff.
NS_LOG_RELEASE(hdr, 0, "nsStringBuffer");

View File

@ -79,10 +79,13 @@ nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint3
size_type curCapacity = Capacity();
// If |capacity > size_type(-1)/2|, then our doubling algorithm may not be
// If |capacity > kMaxCapacity|, then our doubling algorithm may not be
// able to allocate it. Just bail out in cases like that. We don't want
// to be allocating 2GB+ strings anyway.
if (capacity > size_type(-1)/2) {
PR_STATIC_ASSERT((sizeof(nsStringBuffer) & 0x1) == 0);
const size_type kMaxCapacity =
(size_type(-1)/2 - sizeof(nsStringBuffer)) / sizeof(char_type) - 2;
if (capacity > kMaxCapacity) {
// Also assert for |capacity| equal to |size_type(-1)|, since we used to
// use that value to flag immutability.
NS_ASSERTION(capacity != size_type(-1), "Bogus capacity");
@ -100,15 +103,13 @@ nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint3
return PR_TRUE;
}
if (curCapacity > 0)
{
// use doubling algorithm when forced to increase available
// capacity.
PRUint32 temp = curCapacity;
while (temp < capacity)
temp <<= 1;
capacity = temp;
}
// Use doubling algorithm when forced to increase available capacity.
size_type temp = curCapacity;
while (temp < capacity)
temp <<= 1;
NS_ASSERTION(NS_MIN(temp, kMaxCapacity) >= capacity,
"should have hit the early return at the top");
capacity = NS_MIN(temp, kMaxCapacity);
}
//

View File

@ -1069,6 +1069,92 @@ static PRBool test_strip_chars()
NS_LITERAL_STRING(" foo"), 1);
}
static PRBool test_huge_capacity()
{
nsString a, b, c, d, e, f, g, h, i, j, k, l, m, n;
nsCString n1;
PRBool fail = PR_FALSE;
#undef ok
#define ok(x) { fail |= !(x); }
ok(a.SetCapacity(1));
ok(!a.SetCapacity(nsString::size_type(-1)/2));
ok(a.SetCapacity(0)); // free the allocated memory
ok(b.SetCapacity(1));
ok(!b.SetCapacity(nsString::size_type(-1)/2 - 1));
ok(b.SetCapacity(0));
ok(c.SetCapacity(1));
ok(!c.SetCapacity(nsString::size_type(-1)/2));
ok(c.SetCapacity(0));
ok(!d.SetCapacity(nsString::size_type(-1)/2 - 1));
ok(!d.SetCapacity(nsString::size_type(-1)/2));
ok(d.SetCapacity(0));
ok(!e.SetCapacity(nsString::size_type(-1)/4));
ok(!e.SetCapacity(nsString::size_type(-1)/4 + 1));
ok(e.SetCapacity(0));
ok(!f.SetCapacity(nsString::size_type(-1)/2));
ok(f.SetCapacity(0));
ok(!g.SetCapacity(nsString::size_type(-1)/4 + 1000));
ok(!g.SetCapacity(nsString::size_type(-1)/4 + 1001));
ok(g.SetCapacity(0));
ok(!h.SetCapacity(nsString::size_type(-1)/4+1));
ok(!h.SetCapacity(nsString::size_type(-1)/2));
ok(h.SetCapacity(0));
ok(i.SetCapacity(1));
ok(i.SetCapacity(nsString::size_type(-1)/4 - 1000));
ok(!i.SetCapacity(nsString::size_type(-1)/4 + 1));
ok(i.SetCapacity(0));
ok(j.SetCapacity(nsString::size_type(-1)/4 - 1000));
ok(!j.SetCapacity(nsString::size_type(-1)/4 + 1));
ok(j.SetCapacity(0));
ok(k.SetCapacity(nsString::size_type(-1)/8 - 1000));
ok(k.SetCapacity(nsString::size_type(-1)/4 - 1001));
ok(k.SetCapacity(nsString::size_type(-1)/4 - 998));
ok(!k.SetCapacity(nsString::size_type(-1)/4 + 1));
ok(k.SetCapacity(0));
ok(l.SetCapacity(nsString::size_type(-1)/8));
ok(l.SetCapacity(nsString::size_type(-1)/8 + 1));
ok(l.SetCapacity(nsString::size_type(-1)/8 + 2));
ok(l.SetCapacity(0));
ok(m.SetCapacity(nsString::size_type(-1)/8 + 1000));
ok(m.SetCapacity(nsString::size_type(-1)/8 + 1001));
ok(m.SetCapacity(0));
ok(n.SetCapacity(nsString::size_type(-1)/8+1));
ok(!n.SetCapacity(nsString::size_type(-1)/4));
ok(n.SetCapacity(0));
ok(n.SetCapacity(0));
ok(n.SetCapacity((nsString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 2 - 2));
ok(n.SetCapacity(0));
ok(!n.SetCapacity((nsString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 2 - 1));
ok(n.SetCapacity(0));
ok(n1.SetCapacity(0));
ok(n1.SetCapacity((nsCString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 1 - 2));
ok(n1.SetCapacity(0));
ok(!n1.SetCapacity((nsCString::size_type(-1)/2 - sizeof(nsStringBuffer)) / 1 - 1));
ok(n1.SetCapacity(0));
// Ignore the result if the address space is less than 64-bit because
// some of the allocations above will exhaust the address space.
if (sizeof(void*) >= 8) {
return !fail;
}
return PR_TRUE;
}
//----
typedef PRBool (*TestFunc)();
@ -1119,6 +1205,7 @@ tests[] =
{ "test_string_tointeger", test_string_tointeger },
{ "test_parse_string", test_parse_string },
{ "test_strip_chars", test_strip_chars },
{ "test_huge_capacity", test_huge_capacity },
{ nsnull, nsnull }
};
@ -1132,6 +1219,8 @@ int main(int argc, char **argv)
if (argc > 1)
count = atoi(argv[1]);
NS_LogInit();
while (count--)
{
for (const Test* t = tests; t->name != nsnull; ++t)