Changeset 167336 in webkit


Ignore:
Timestamp:
Apr 15, 2014 4:33:11 PM (10 years ago)
Author:
fpizlo@apple.com
Message:

compileMakeRope does not emit necessary bounds checks
https://bugs.webkit.org/show_bug.cgi?id=130684
<rdar://problem/16398388>

Reviewed by Oliver Hunt.

Add string length bounds checks in a bunch of places. We should never allow a string
to have a length greater than 231-1 because it's not clear that the language has
semantics for it and because there is code that assumes that this cannot happen.

Also add a bunch of tests to that effect to cover the various ways in which this was
previously allowed to happen.

  • dfg/DFGOperations.cpp:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileMakeRope):

  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::LowerDFGToLLVM::compileMakeRope):

  • runtime/JSString.cpp:

(JSC::JSRopeString::RopeBuilder::expand):

  • runtime/JSString.h:

(JSC::JSString::create):
(JSC::JSRopeString::RopeBuilder::append):
(JSC::JSRopeString::RopeBuilder::release):
(JSC::JSRopeString::append):

  • runtime/Operations.h:

(JSC::jsString):
(JSC::jsStringFromRegisterArray):
(JSC::jsStringFromArguments):

  • runtime/StringPrototype.cpp:

(JSC::stringProtoFuncIndexOf):
(JSC::stringProtoFuncSlice):
(JSC::stringProtoFuncSubstring):
(JSC::stringProtoFuncToLowerCase):

  • tests/stress/make-large-string-jit-strcat.js: Added.

(foo):

  • tests/stress/make-large-string-jit.js: Added.

(foo):

  • tests/stress/make-large-string-strcat.js: Added.
  • tests/stress/make-large-string.js: Added.
Location:
trunk/Source/JavaScriptCore
Files:
4 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r167329 r167336  
     12014-04-15  Filip Pizlo  <fpizlo@apple.com>
     2
     3        compileMakeRope does not emit necessary bounds checks
     4        https://bugs.webkit.org/show_bug.cgi?id=130684
     5        <rdar://problem/16398388>
     6
     7        Reviewed by Oliver Hunt.
     8       
     9        Add string length bounds checks in a bunch of places. We should never allow a string
     10        to have a length greater than 2^31-1 because it's not clear that the language has
     11        semantics for it and because there is code that assumes that this cannot happen.
     12       
     13        Also add a bunch of tests to that effect to cover the various ways in which this was
     14        previously allowed to happen.
     15
     16        * dfg/DFGOperations.cpp:
     17        * dfg/DFGSpeculativeJIT.cpp:
     18        (JSC::DFG::SpeculativeJIT::compileMakeRope):
     19        * ftl/FTLLowerDFGToLLVM.cpp:
     20        (JSC::FTL::LowerDFGToLLVM::compileMakeRope):
     21        * runtime/JSString.cpp:
     22        (JSC::JSRopeString::RopeBuilder::expand):
     23        * runtime/JSString.h:
     24        (JSC::JSString::create):
     25        (JSC::JSRopeString::RopeBuilder::append):
     26        (JSC::JSRopeString::RopeBuilder::release):
     27        (JSC::JSRopeString::append):
     28        * runtime/Operations.h:
     29        (JSC::jsString):
     30        (JSC::jsStringFromRegisterArray):
     31        (JSC::jsStringFromArguments):
     32        * runtime/StringPrototype.cpp:
     33        (JSC::stringProtoFuncIndexOf):
     34        (JSC::stringProtoFuncSlice):
     35        (JSC::stringProtoFuncSubstring):
     36        (JSC::stringProtoFuncToLowerCase):
     37        * tests/stress/make-large-string-jit-strcat.js: Added.
     38        (foo):
     39        * tests/stress/make-large-string-jit.js: Added.
     40        (foo):
     41        * tests/stress/make-large-string-strcat.js: Added.
     42        * tests/stress/make-large-string.js: Added.
     43
    1442014-04-15  Julien Brianceau  <jbriance@cisco.com>
    245
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r167036 r167336  
    969969    VM& vm = exec->vm();
    970970    NativeCallFrameTracer tracer(&vm, exec);
     971   
     972    if (static_cast<int32_t>(left->length() + right->length()) < 0) {
     973        throwOutOfMemoryError(exec);
     974        return 0;
     975    }
    971976
    972977    return JSRopeString::create(vm, left, right);
     
    977982    VM& vm = exec->vm();
    978983    NativeCallFrameTracer tracer(&vm, exec);
     984
     985    Checked<int32_t, RecordOverflow> length = a->length();
     986    length += b->length();
     987    length += c->length();
     988    if (length.hasOverflowed()) {
     989        throwOutOfMemoryError(exec);
     990        return 0;
     991    }
    979992
    980993    return JSRopeString::create(vm, a, b, c);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r167325 r167336  
    27942794    m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfFlags()), scratchGPR);
    27952795    m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfLength()), allocatorGPR);
     2796    if (!ASSERT_DISABLED) {
     2797        JITCompiler::Jump ok = m_jit.branch32(
     2798            JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
     2799        m_jit.breakpoint();
     2800        ok.link(&m_jit);
     2801    }
    27962802    for (unsigned i = 1; i < numOpGPRs; ++i) {
    27972803        m_jit.and32(JITCompiler::Address(opGPRs[i], JSString::offsetOfFlags()), scratchGPR);
    2798         m_jit.add32(JITCompiler::Address(opGPRs[i], JSString::offsetOfLength()), allocatorGPR);
     2804        speculationCheck(
     2805            Uncountable, JSValueSource(), nullptr,
     2806            m_jit.branchAdd32(
     2807                JITCompiler::Overflow,
     2808                JITCompiler::Address(opGPRs[i], JSString::offsetOfLength()), allocatorGPR));
    27992809    }
    28002810    m_jit.and32(JITCompiler::TrustedImm32(JSString::Is8Bit), scratchGPR);
    28012811    m_jit.store32(scratchGPR, JITCompiler::Address(resultGPR, JSString::offsetOfFlags()));
     2812    if (!ASSERT_DISABLED) {
     2813        JITCompiler::Jump ok = m_jit.branch32(
     2814            JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0));
     2815        m_jit.breakpoint();
     2816        ok.link(&m_jit);
     2817    }
    28022818    m_jit.store32(allocatorGPR, JITCompiler::Address(resultGPR, JSString::offsetOfLength()));
    28032819   
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

    r167325 r167336  
    29442944        for (unsigned i = 1; i < numKids; ++i) {
    29452945            flags = m_out.bitAnd(flags, m_out.load32(kids[i], m_heaps.JSString_flags));
    2946             length = m_out.add(length, m_out.load32(kids[i], m_heaps.JSString_length));
     2946            LValue lengthAndOverflow = m_out.addWithOverflow32(
     2947                length, m_out.load32(kids[i], m_heaps.JSString_length));
     2948            speculate(Uncountable, noValue(), 0, m_out.extractValue(lengthAndOverflow, 1));
     2949            length = m_out.extractValue(lengthAndOverflow, 0);
    29472950        }
    29482951        m_out.store32(
  • trunk/Source/JavaScriptCore/runtime/JSString.cpp

    r166837 r167336  
    3939    ASSERT(m_index == JSRopeString::s_maxInternalRopeLength);
    4040    JSString* jsString = m_jsString;
     41    RELEASE_ASSERT(jsString);
    4142    m_jsString = jsStringBuilder(&m_vm);
    4243    m_index = 0;
  • trunk/Source/JavaScriptCore/runtime/JSString.h

    r166837 r167336  
    22 *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
    33 *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
    4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
     4 *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
    55 *
    66 *  This library is free software; you can redistribute it and/or
     
    124124        {
    125125            ASSERT(value);
    126             size_t length = value->length();
     126            int32_t length = value->length();
     127            RELEASE_ASSERT(length >= 0);
    127128            size_t cost = value->cost();
    128129            JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
     
    229230            }
    230231
    231             void append(JSString* jsString)
     232            bool append(JSString* jsString)
    232233            {
    233234                if (m_index == JSRopeString::s_maxInternalRopeLength)
    234235                    expand();
     236                if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) {
     237                    m_jsString = 0;
     238                    return false;
     239                }
    235240                m_jsString->append(m_vm, m_index++, jsString);
     241                return true;
    236242            }
    237243
    238244            JSRopeString* release()
    239245            {
     246                RELEASE_ASSERT(m_jsString);
    240247                JSRopeString* tmp = m_jsString;
    241248                m_jsString = 0;
     
    287294            m_fibers[index].set(vm, this, jsString);
    288295            m_length += jsString->m_length;
     296            RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0);
    289297            setIs8Bit(is8Bit() && jsString->is8Bit());
    290298        }
  • trunk/Source/JavaScriptCore/runtime/Operations.h

    r164764 r167336  
    3939    VM& vm = exec->vm();
    4040
    41     unsigned length1 = s1->length();
     41    int32_t length1 = s1->length();
    4242    if (!length1)
    4343        return s2;
    44     unsigned length2 = s2->length();
     44    int32_t length2 = s2->length();
    4545    if (!length2)
    4646        return s1;
    47     if ((length1 + length2) < length1)
     47    if ((length1 + length2) < 0)
    4848        return throwOutOfMemoryError(exec);
    4949
     
    5555    VM* vm = &exec->vm();
    5656
    57     unsigned length1 = u1.length();
    58     unsigned length2 = u2.length();
    59     unsigned length3 = u3.length();
     57    int32_t length1 = u1.length();
     58    int32_t length2 = u2.length();
     59    int32_t length3 = u3.length();
     60   
     61    if (length1 < 0 || length2 < 0 || length3 < 0)
     62        return throwOutOfMemoryError(exec);
     63   
    6064    if (!length1)
    6165        return jsString(exec, jsString(vm, u2), jsString(vm, u3));
     
    6569        return jsString(exec, jsString(vm, u1), jsString(vm, u2));
    6670
    67     if ((length1 + length2) < length1)
    68         return throwOutOfMemoryError(exec);
    69     if ((length1 + length2 + length3) < length3)
     71    if ((length1 + length2) < 0)
     72        return throwOutOfMemoryError(exec);
     73    if ((length1 + length2 + length3) < 0)
    7074        return throwOutOfMemoryError(exec);
    7175
     
    7882    JSRopeString::RopeBuilder ropeBuilder(*vm);
    7983
    80     unsigned oldLength = 0;
    81 
    8284    for (unsigned i = 0; i < count; ++i) {
    8385        JSValue v = strings[-static_cast<int>(i)].jsValue();
    84         ropeBuilder.append(v.toString(exec));
    85 
    86         if (ropeBuilder.length() < oldLength) // True for overflow
     86        if (!ropeBuilder.append(v.toString(exec)))
    8787            return throwOutOfMemoryError(exec);
    88         oldLength = ropeBuilder.length();
    8988    }
    9089
     
    9897    ropeBuilder.append(thisValue.toString(exec));
    9998
    100     unsigned oldLength = 0;
    101 
    10299    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
    103100        JSValue v = exec->argument(i);
    104         ropeBuilder.append(v.toString(exec));
    105 
    106         if (ropeBuilder.length() < oldLength) // True for overflow
     101        if (!ropeBuilder.append(v.toString(exec)))
    107102            return throwOutOfMemoryError(exec);
    108         oldLength = ropeBuilder.length();
    109103    }
    110104
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r166493 r167336  
    763763    if (!a1.isUndefined()) {
    764764        int len = thisJSString->length();
     765        RELEASE_ASSERT(len >= 0);
    765766        if (a1.isUInt32())
    766767            pos = std::min<uint32_t>(a1.asUInt32(), len);
     
    917918    String s = thisValue.toString(exec)->value(exec);
    918919    int len = s.length();
     920    RELEASE_ASSERT(len >= 0);
    919921
    920922    JSValue a0 = exec->argument(0);
     
    12281230    JSValue a1 = exec->argument(1);
    12291231    int len = jsString->length();
     1232    RELEASE_ASSERT(len >= 0);
    12301233
    12311234    double start = a0.toNumber(exec);
     
    12651268    if (!sSize)
    12661269        return JSValue::encode(sVal);
     1270    RELEASE_ASSERT(sSize >= 0);
    12671271
    12681272    StringImpl* ourImpl = s.impl();
Note: See TracChangeset for help on using the changeset viewer.