Bug 1253137 - Baldr: fix unknown-section handling (r=sunfish)
authorLuke Wagner <luke@mozilla.com>
Fri, 04 Mar 2016 11:03:21 -0600
changeset 323136 6bd419f5a9d04670b250e69e96049e38e7e181f1
parent 323135 374edef94056db96e54aef951ce678055c8acf83
child 323137 e3d938a82d2c670e286b55645ce03a7d04a4c096
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1253137
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1253137 - Baldr: fix unknown-section handling (r=sunfish) MozReview-Commit-ID: 9R4S8OlxAbZ
js/src/asmjs/Wasm.cpp
js/src/asmjs/WasmBinary.h
js/src/asmjs/WasmText.cpp
js/src/jit-test/tests/wasm/binary.js
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -1242,24 +1242,21 @@ DecodeModule(JSContext* cx, UniqueChars 
     if (!DecodeFunctionBodiesSection(cx, d, mg))
         return false;
 
     if (!DecodeDataSection(cx, d, heap))
         return false;
 
     CacheableCharsVector funcNames;
 
-    while (!d.readCStringIf(EndLabel)) {
+    while (!d.done()) {
         if (!d.skipSection())
-            return Fail(cx, d, "unable to skip unknown section");
+            return Fail(cx, d, "failed to skip unknown section at end");
     }
 
-    if (!d.done())
-        return Fail(cx, d, "failed to consume all bytes of module");
-
     UniqueModuleData module;
     UniqueStaticLinkData staticLink;
     SlowFunctionVector slowFuncs(cx);
     if (!mg.finish(Move(funcNames), &module, &staticLink, exportMap, &slowFuncs))
         return false;
 
     moduleObj.set(WasmModuleObject::create(cx));
     if (!moduleObj)
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -709,17 +709,23 @@ class Decoder
         uint32_t afterSize = cur_ - beg_;
         cur_ = beg_ + currentOffset;
         return size == (currentOffset - afterSize);
     }
     MOZ_WARN_UNUSED_RESULT bool skipSection() {
         uint32_t size;
         if (!readVarU32(&size) || bytesRemain() < size)
             return false;
-        cur_ += size;
+        const uint8_t* begin = cur_;
+        uint32_t idSize;
+        if (!readVarU32(&idSize) || bytesRemain() < idSize)
+            return false;
+        if (uint32_t(cur_ - begin) > size)
+            return false;
+        cur_ = begin + size;
         return true;
     }
 
     // The infallible "unchecked" decoding functions can be used when we are
     // sure that the bytecode is well-formed (by construction or due to previous
     // validation).
 
     uint32_t uncheckedReadFixedU32() {
--- a/js/src/asmjs/WasmText.cpp
+++ b/js/src/asmjs/WasmText.cpp
@@ -4049,19 +4049,16 @@ EncodeModule(WasmAstModule& module)
         return nullptr;
 
     if (!EncodeFunctionBodiesSection(e, module))
         return nullptr;
 
     if (!EncodeDataSection(e, module))
         return nullptr;
 
-    if (!e.writeCString(EndLabel))
-        return nullptr;
-
     return Move(bytecode);
 }
 
 /*****************************************************************************/
 
 UniqueBytecode
 wasm::TextToBinary(const char16_t* text, UniqueChars* error)
 {
--- a/js/src/jit-test/tests/wasm/binary.js
+++ b/js/src/jit-test/tests/wasm/binary.js
@@ -18,17 +18,17 @@ const declLabel = "decl";
 const tableLabel = "table";
 const importLabel = "import";
 const exportLabel = "export";
 const funcLabel = "func";
 const dataLabel = "data";
 
 const magicError = /failed to match magic number/;
 const versionError = /failed to match binary version/;
-const extraError = /failed to consume all bytes of module/;
+const unknownSectionError = /failed to skip unknown section at end/;
 const sectionError = /failed to start section/;
 
 const I32Code = 0;
 const I64Code = 1;
 const F32Code = 2;
 const F64Code = 3;
 const I32x4Code = 4;
 const F32x4Code = 5;
@@ -59,22 +59,28 @@ assertErrorMessage(() => wasmEval(toBuf(
 assertErrorMessage(() => wasmEval(toBuf([42])), TypeError, magicError);
 assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2])), TypeError, magicError);
 assertErrorMessage(() => wasmEval(toBuf([1,2,3,4])), TypeError, magicError);
 assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3])), TypeError, versionError);
 assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3, 1])), TypeError, versionError);
 assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3, ver0])), TypeError, versionError);
 assertErrorMessage(() => wasmEval(toBuf([magic0, magic1, magic2, magic3, ver0, ver1, ver2])), TypeError, versionError);
 
-var o = wasmEval(toBuf(moduleHeaderThen(0)));
+var o = wasmEval(toBuf(moduleHeaderThen()));
 assertEq(Object.getOwnPropertyNames(o).length, 0);
 
+wasmEval(toBuf(moduleHeaderThen(1, 0)));        // unknown section containing 0-length string
+wasmEval(toBuf(moduleHeaderThen(2, 1, 0)));     // unknown section containing 1-length string ("\0")
+wasmEval(toBuf(moduleHeaderThen(1, 0,  1, 0)));
+wasmEval(toBuf(moduleHeaderThen(1, 0,  2, 1, 0)));
+wasmEval(toBuf(moduleHeaderThen(1, 0,  2, 1, 0)));
+
 assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(1))), TypeError, sectionError);
-assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(0, 0))), TypeError, extraError);
 assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(0, 1))), TypeError, sectionError);
+assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(0, 0))), TypeError, unknownSectionError);
 
 function cstring(name) {
     return (name + '\0').split('').map(c => c.charCodeAt(0));
 }
 
 function string(name) {
     return name.split('').map(c => c.charCodeAt(0));
 }
@@ -83,17 +89,16 @@ function moduleWithSections(sectionArray
     var bytes = moduleHeaderThen();
     for (let section of sectionArray) {
         var nameLength = varU32(section.name.length);
         bytes.push(...varU32(nameLength.length + section.name.length + section.body.length));
         bytes.push(...nameLength);
         bytes.push(...string(section.name));
         bytes.push(...section.body);
     }
-    bytes.push(0);
     return bytes;
 }
 
 function sigSection(sigs) {
     var body = [];
     body.push(...varU32(sigs.length));
     for (let sig of sigs) {
         body.push(...varU32(sig.args.length));