Changeset 209874 in webkit


Ignore:
Timestamp:
Dec 15, 2016 2:08:38 PM (7 years ago)
Author:
jfbastien@apple.com
Message:

JSTests:
WebAssembly API: improve data section errors
https://bugs.webkit.org/show_bug.cgi?id=165733

Reviewed by Keith Miller.

  • wasm/js-api/element-data.js: Added.

(ElementBeforeData.set const):
(ElementBeforeData): check the order of initialization, which is observable on failure

  • wasm/js-api/test_Data.js:

(DataSectionWithoutMemory):
(DataSectionOffTheEnd): Deleted.
(DataSectionPartlyOffTheEnd): Deleted.
(DataSectionEmptyOffTheEnd): Deleted.
(DataSectionSeenByStart): Deleted.

Source/JavaScriptCore:
WebAssembly API: improve data section errors, initialize after Element
https://bugs.webkit.org/show_bug.cgi?id=165733

Reviewed by Keith Miller.

  • wasm/WasmModuleParser.cpp:

(JSC::Wasm::ModuleParser::parseData): Data section without Memory section or import is a validation error

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::dataSegmentFail):
(JSC::WebAssemblyModuleRecord::evaluate): tighten checks (though the spec isn't fully baked), and move after Element initialization

Location:
trunk
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r209866 r209874  
     12016-12-15  JF Bastien  <jfbastien@apple.com>
     2
     3        WebAssembly API: improve data section errors
     4        https://bugs.webkit.org/show_bug.cgi?id=165733
     5
     6        Reviewed by Keith Miller.
     7
     8        * wasm/js-api/element-data.js: Added.
     9        (ElementBeforeData.set const):
     10        (ElementBeforeData): check the order of initialization, which is observable on failure
     11        * wasm/js-api/test_Data.js:
     12        (DataSectionWithoutMemory):
     13        (DataSectionOffTheEnd): Deleted.
     14        (DataSectionPartlyOffTheEnd): Deleted.
     15        (DataSectionEmptyOffTheEnd): Deleted.
     16        (DataSectionSeenByStart): Deleted.
     17
    1182016-12-15  Keith Miller  <keith_miller@apple.com>
    219
  • trunk/JSTests/wasm/js-api/test_Data.js

    r209651 r209874  
    55const pageSizeInBytes = 64 * 1024;
    66const memoryDescription = { initial: memSizeInPages, maximum: memSizeInPages };
     7const emptyMemory = { initial: 0, maximum: 2 };
    78
    89// FIXME Some corner cases are ill-specified: https://github.com/WebAssembly/design/issues/897
     10
     11const assertMemoryAllZero = memory => {
     12    const buffer = new Uint8Array(memory.buffer);
     13    for (let idx = 0; idx < buffer.length; ++idx) {
     14        const value = buffer[idx];
     15        assert.eq(value, 0x00);
     16    }
     17};
    918
    1019(function DataSection() {
     
    3746})();
    3847
     48(function DataSectionWithoutMemory() {
     49    const builder = (new Builder())
     50        .Type().End()
     51        .Data()
     52          .Segment([0xff]).Offset(0).End()
     53        .End();
     54    const bin = builder.WebAssembly().get();
     55    assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `couldn't parse section Data: Data segments (evaluating 'new WebAssembly.Module(bin)')`);
     56})();
     57
     58(function EmptyDataSectionWithoutMemory() {
     59    const builder = (new Builder())
     60        .Type().End()
     61        .Data()
     62          .Segment([]).Offset(0).End()
     63        .End();
     64    const bin = builder.WebAssembly().get();
     65    assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `couldn't parse section Data: Data segments (evaluating 'new WebAssembly.Module(bin)')`);
     66})();
     67
     68(function DataSectionBiggerThanMemory() {
     69    const builder = (new Builder())
     70        .Type().End()
     71        .Import().Memory("imp", "memory", memoryDescription).End()
     72        .Data()
     73          .Segment(Array(memSizeInPages * pageSizeInBytes + 1).fill(0xff)).Offset(0).End()
     74        .End();
     75    const bin = builder.WebAssembly().get();
     76    const module = new WebAssembly.Module(bin);
     77    const memory = new WebAssembly.Memory(memoryDescription);
     78    assert.throws(() => new WebAssembly.Instance(module, { imp: { memory: memory } }), RangeError, `Invalid data segment initialization: segment of 65537 bytes memory of 65536 bytes, at offset 0, segment is too big`);
     79    assertMemoryAllZero(memory);
     80})();
     81
    3982(function DataSectionOffTheEnd() {
    4083    const builder = (new Builder())
     
    4790    const module = new WebAssembly.Module(bin);
    4891    const memory = new WebAssembly.Memory(memoryDescription);
    49     assert.throws(() => new WebAssembly.Instance(module, { imp: { memory: memory } }), RangeError, `Data segment initializes memory out of range`);
    50     const buffer = new Uint8Array(memory.buffer);
    51     for (let idx = 0; idx < memSizeInPages * pageSizeInBytes; ++idx) {
    52         const value = buffer[idx];
    53         assert.eq(value, 0x00);
    54     }
     92    assert.throws(() => new WebAssembly.Instance(module, { imp: { memory: memory } }), RangeError, `Invalid data segment initialization: segment of 1 bytes memory of 65536 bytes, at offset 65536, segment writes outside of memory`);
     93    assertMemoryAllZero(memory);
    5594})();
    5695
     
    65104    const module = new WebAssembly.Module(bin);
    66105    const memory = new WebAssembly.Memory(memoryDescription);
    67     assert.throws(() => new WebAssembly.Instance(module, { imp: { memory: memory } }), RangeError, `Data segment initializes memory out of range`);
    68     const buffer = new Uint8Array(memory.buffer);
    69     for (let idx = 0; idx < memSizeInPages * pageSizeInBytes; ++idx) {
    70         const value = buffer[idx];
    71         assert.eq(value, 0x00);
    72     }
     106    assert.throws(() => new WebAssembly.Instance(module, { imp: { memory: memory } }), RangeError, `Invalid data segment initialization: segment of 2 bytes memory of 65536 bytes, at offset 65535, segment writes outside of memory`);
     107    assertMemoryAllZero(memory);
    73108})();
    74109
     
    84119    const memory = new WebAssembly.Memory(memoryDescription);
    85120    const instance = new WebAssembly.Instance(module, { imp: { memory: memory } });
    86     const buffer = new Uint8Array(memory.buffer);
    87     for (let idx = 0; idx < memSizeInPages * pageSizeInBytes; ++idx) {
    88         const value = buffer[idx];
    89         assert.eq(value, 0x00);
    90     }
     121    assertMemoryAllZero(memory);
     122})();
     123
     124(function DataSectionEmptyOffTheEndWithEmptyMemory() {
     125    const builder = (new Builder())
     126        .Type().End()
     127        .Import().Memory("imp", "memory", emptyMemory).End()
     128        .Data()
     129          .Segment([]).Offset(memSizeInPages * pageSizeInBytes).End()
     130        .End();
     131    const bin = builder.WebAssembly().get();
     132    const module = new WebAssembly.Module(bin);
     133    const memory = new WebAssembly.Memory(emptyMemory);
     134    const instance = new WebAssembly.Instance(module, { imp: { memory: memory } });
     135    assertMemoryAllZero(memory);
    91136})();
    92137
  • trunk/Source/JavaScriptCore/ChangeLog

    r209872 r209874  
     12016-12-15  JF Bastien  <jfbastien@apple.com>
     2
     3        WebAssembly API: improve data section errors, initialize after Element
     4        https://bugs.webkit.org/show_bug.cgi?id=165733
     5
     6        Reviewed by Keith Miller.
     7
     8        * wasm/WasmModuleParser.cpp:
     9        (JSC::Wasm::ModuleParser::parseData): Data section without Memory section or import is a validation error
     10        * wasm/js/WebAssemblyModuleRecord.cpp:
     11        (JSC::dataSegmentFail):
     12        (JSC::WebAssemblyModuleRecord::evaluate): tighten checks (though the spec isn't fully baked), and move after Element initialization
     13
    1142016-12-15  Keith Miller  <keith_miller@apple.com>
    215
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp

    r209850 r209874  
    725725{
    726726    uint32_t segmentCount;
     727    if (!m_module->memory)
     728        return false;
    727729    if (!parseVarUInt32(segmentCount)
    728730        || segmentCount == std::numeric_limits<uint32_t>::max()
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

    r209850 r209874  
    195195}
    196196
     197template <typename Scope, typename N, typename ...Args>
     198NEVER_INLINE static JSValue dataSegmentFail(ExecState* state, Scope& scope, N memorySize, N segmentSize, N offset, Args... args)
     199{
     200    return throwException(state, scope, createRangeError(state, makeString(ASCIILiteral("Invalid data segment initialization: segment of "), String::number(segmentSize), ASCIILiteral(" bytes memory of "), String::number(memorySize), ASCIILiteral(" bytes, at offset "), String::number(offset), args...)));
     201}
     202
    197203JSValue WebAssemblyModuleRecord::evaluate(ExecState* state)
    198204{
    199205    VM& vm = state->vm();
    200206    auto scope = DECLARE_THROW_SCOPE(vm);
    201 
    202     if (JSWebAssemblyMemory* jsMemory = m_instance->memory()) {
    203         uint8_t* memory = reinterpret_cast<uint8_t*>(jsMemory->memory()->memory());
    204         auto sizeInBytes = jsMemory->memory()->size();
    205         if (memory) {
    206             const Vector<Wasm::Segment::Ptr>& data = m_instance->module()->moduleInformation().data;
    207             for (auto& segment : data) {
    208                 if (segment->sizeInBytes) {
    209                     if (sizeInBytes < segment->sizeInBytes
    210                         || segment->offset > sizeInBytes
    211                         || segment->offset > sizeInBytes - segment->sizeInBytes)
    212                         return throwException(state, scope, createRangeError(state, ASCIILiteral("Data segment initializes memory out of range")));
    213                     memcpy(memory + segment->offset, &segment->byte(0), segment->sizeInBytes);
    214                 }
    215             }
    216         }
    217     }
    218207
    219208    {
     
    262251    }
    263252
     253    {
     254        const Vector<Wasm::Segment::Ptr>& data = m_instance->module()->moduleInformation().data;
     255        JSWebAssemblyMemory* jsMemory = m_instance->memory();
     256        if (!data.isEmpty()) {
     257            RELEASE_ASSERT(jsMemory); // It is a validation error for a Data section to exist without a Memory section or import.
     258            uint8_t* memory = reinterpret_cast<uint8_t*>(jsMemory->memory()->memory());
     259            RELEASE_ASSERT(memory);
     260            auto sizeInBytes = jsMemory->memory()->size();
     261            for (auto& segment : data) {
     262                if (segment->sizeInBytes) {
     263                    if (UNLIKELY(sizeInBytes < segment->sizeInBytes))
     264                        return dataSegmentFail(state, scope, sizeInBytes, segment->sizeInBytes, segment->offset, ASCIILiteral(", segment is too big"));
     265                    if (UNLIKELY(segment->offset > sizeInBytes - segment->sizeInBytes))
     266                        return dataSegmentFail(state, scope, sizeInBytes, segment->sizeInBytes, segment->offset, ASCIILiteral(", segment writes outside of memory"));
     267                    memcpy(memory + segment->offset, &segment->byte(0), segment->sizeInBytes);
     268                }
     269            }
     270        }
     271    }
     272
    264273    if (WebAssemblyFunction* startFunction = m_startFunction.get()) {
    265274        ProtoCallFrame protoCallFrame;
     
    268277        RETURN_IF_EXCEPTION(scope, { });
    269278    }
     279
    270280    return jsUndefined();
    271281}
Note: See TracChangeset for help on using the changeset viewer.