Changeset 202173 in webkit


Ignore:
Timestamp:
Jun 17, 2016, 12:22:02 PM (9 years ago)
Author:
mark.lam@apple.com
Message:

OOM Assertion failure in JSON.stringify.
https://bugs.webkit.org/show_bug.cgi?id=158794
<rdar://problem/26826254>

Reviewed by Saam Barati.

The bug was actually in StringBuilder::appendQuotedJSONString() where it failed
to detect an imminent unsigned int overflow. The fix is to use Checked<unsigned>
for the needed math, and RELEASE_ASSERT afterwards that we did not overflow.

I also added more assertions to detect sooner if any there are any problems with
StringBuilder's m_buffer or m_length being incorrectly sized. These assertions
have been run on the JSC and layout tests without any issue.

  • wtf/text/StringBuilder.cpp:

(WTF::StringBuilder::resize):
(WTF::StringBuilder::allocateBuffer):
(WTF::StringBuilder::allocateBufferUpConvert):
(WTF::StringBuilder::reallocateBuffer<LChar>):
(WTF::StringBuilder::reallocateBuffer<UChar>):
(WTF::StringBuilder::reserveCapacity):
(WTF::StringBuilder::appendUninitializedSlow):
(WTF::StringBuilder::append):
(WTF::StringBuilder::appendQuotedJSONString):

  • wtf/text/StringBuilder.h:

(WTF::StringBuilder::swap):

Location:
trunk/Source/WTF
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r202157 r202173  
     12016-06-17  Mark Lam  <mark.lam@apple.com>
     2
     3        OOM Assertion failure in JSON.stringify.
     4        https://bugs.webkit.org/show_bug.cgi?id=158794
     5        <rdar://problem/26826254>
     6
     7        Reviewed by Saam Barati.
     8
     9        The bug was actually in StringBuilder::appendQuotedJSONString() where it failed
     10        to detect an imminent unsigned int overflow.  The fix is to use Checked<unsigned>
     11        for the needed math, and RELEASE_ASSERT afterwards that we did not overflow.
     12
     13        I also added more assertions to detect sooner if any there are any problems with
     14        StringBuilder's m_buffer or m_length being incorrectly sized.  These assertions
     15        have been run on the JSC and layout tests without any issue.
     16
     17        * wtf/text/StringBuilder.cpp:
     18        (WTF::StringBuilder::resize):
     19        (WTF::StringBuilder::allocateBuffer):
     20        (WTF::StringBuilder::allocateBufferUpConvert):
     21        (WTF::StringBuilder::reallocateBuffer<LChar>):
     22        (WTF::StringBuilder::reallocateBuffer<UChar>):
     23        (WTF::StringBuilder::reserveCapacity):
     24        (WTF::StringBuilder::appendUninitializedSlow):
     25        (WTF::StringBuilder::append):
     26        (WTF::StringBuilder::appendQuotedJSONString):
     27        * wtf/text/StringBuilder.h:
     28        (WTF::StringBuilder::swap):
     29
    1302016-06-14  Filip Pizlo  <fpizlo@apple.com>
    231
  • trunk/Source/WTF/wtf/text/StringBuilder.cpp

    r201782 r202173  
    11/*
    2  * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2010, 2013, 2016 Apple Inc. All rights reserved.
    33 * Copyright (C) 2012 Google Inc. All rights reserved.
    44 *
     
    8181        }
    8282        m_length = newSize;
     83        ASSERT(m_buffer->length() >= m_length);
    8384        return;
    8485    }
     
    104105    m_buffer = WTFMove(buffer);
    105106    m_string = String();
     107    ASSERT(m_buffer->length() == requiredLength);
    106108}
    107109
     
    118120    m_buffer = WTFMove(buffer);
    119121    m_string = String();
     122    ASSERT(m_buffer->length() == requiredLength);
    120123}
    121124
     
    125128{
    126129    ASSERT(m_is8Bit);
     130    ASSERT(requiredLength >= m_length);
    127131    // Copy the existing data into a new buffer, set result to point to the end of the existing data.
    128132    auto buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16);
     
    135139    m_buffer = WTFMove(buffer);
    136140    m_string = String();
     141    ASSERT(m_buffer->length() == requiredLength);
    137142}
    138143
     
    151156    else
    152157        allocateBuffer(m_buffer->characters8(), requiredLength);
     158    ASSERT(m_buffer->length() == requiredLength);
    153159}
    154160
     
    166172    else
    167173        allocateBuffer(m_buffer->characters16(), requiredLength);
     174    ASSERT(m_buffer->length() == requiredLength);
    168175}
    169176
     
    190197        }
    191198    }
     199    ASSERT(!newCapacity || m_buffer->length() >= newCapacity);
    192200}
    193201
     
    235243    CharType* result = getBufferCharacters<CharType>() + m_length;
    236244    m_length = requiredLength;
     245    ASSERT(m_buffer->length() >= m_length);
    237246    return result;
    238247}
     
    268277        }
    269278
    270         memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(length) * sizeof(UChar));       
     279        memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(length) * sizeof(UChar));
    271280        m_length = requiredLength;
    272281    } else
    273282        memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_t>(length) * sizeof(UChar));
     283    ASSERT(m_buffer->length() >= m_length);
    274284}
    275285
     
    413423    // The 2 is for the '"' quotes on each end.
    414424    // The 6 is for characters that need to be \uNNNN encoded.
    415     size_t maximumCapacityRequired = length() + 2 + string.length() * 6;
    416     RELEASE_ASSERT(maximumCapacityRequired < std::numeric_limits<unsigned>::max());
    417     unsigned allocationSize = maximumCapacityRequired;
     425    Checked<unsigned> stringLength = string.length();
     426    Checked<unsigned> maximumCapacityRequired = length();
     427    maximumCapacityRequired += 2 + stringLength * 6;
     428    unsigned allocationSize = maximumCapacityRequired.unsafeGet();
    418429    // This max() is here to allow us to allocate sizes between the range [2^31, 2^32 - 2] because roundUpToPowerOfTwo(1<<31 + some int smaller than 1<<31) == 0.
    419430    allocationSize = std::max(allocationSize, roundUpToPowerOfTwo(allocationSize));
     
    423434    else
    424435        reserveCapacity(allocationSize);
     436    ASSERT(m_buffer->length() >= allocationSize);
    425437
    426438    if (is8Bit()) {
     
    441453        m_length = output - m_bufferCharacters16;
    442454    }
     455    ASSERT(m_buffer->length() >= m_length);
    443456}
    444457
  • trunk/Source/WTF/wtf/text/StringBuilder.h

    r186279 r202173  
    11/*
    2  * Copyright (C) 2009, 2010, 2012, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2009-2010, 2012-2013, 2016 Apple Inc. All rights reserved.
    33 * Copyright (C) 2012 Google Inc. All rights reserved.
    44 *
     
    277277        std::swap(m_is8Bit, stringBuilder.m_is8Bit);
    278278        std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8);
     279        ASSERT(!m_buffer || m_buffer->length() >= m_length);
    279280    }
    280281
Note: See TracChangeset for help on using the changeset viewer.