author | Luke Wagner <luke@mozilla.com> |
Fri, 23 Dec 2016 13:18:03 -0600 | |
changeset 327150 | d01c0cd382843219b3ff12dc4a675d32b29809a7 |
parent 327149 | d98d1548d5dd92e6cb5ad6e7d052e12526e59502 |
child 327151 | ec3d424e593ebce4b99c1857cbf74350245c67b6 |
push id | 85116 |
push user | lwagner@mozilla.com |
push date | Fri, 23 Dec 2016 19:28:24 +0000 |
treeherder | mozilla-inbound@ec3d424e593e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bbouvier |
bugs | 1324008 |
milestone | 53.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
|
--- a/js/src/jit-test/tests/wasm/regress/too-large-frame.js +++ b/js/src/jit-test/tests/wasm/regress/too-large-frame.js @@ -18,12 +18,12 @@ wasmEvalText( } // The wasm baseline compiler cuts off frames at 256KB at the moment; // the test case for bug 1280934 constructed a frame around 512KB so // duplicate that here. function locals() { var s = ""; - for ( var i=0 ; i < 64000 ; i++ ) + for ( var i=0 ; i < 50000 ; i++ ) s += "(local f64)\n"; return s; }
--- a/js/src/jit/arm/Architecture-arm.h +++ b/js/src/jit/arm/Architecture-arm.h @@ -33,17 +33,17 @@ static const uint32_t ION_FRAME_SLACK_SI // These offsets are specific to nunboxing, and capture offsets into the // components of a js::Value. static const int32_t NUNBOX32_TYPE_OFFSET = 4; static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0; static const uint32_t ShadowStackSpace = 0; // How far forward/back can a jump go? Provide a generous buffer for thunks. -static const uint32_t JumpImmediateRange = 25 * 1024 * 1024; +static const uint32_t JumpImmediateRange = 20 * 1024 * 1024; //// // These offsets are related to bailouts. //// // Size of each bailout table entry. On arm, this is presently a single call // (which is wrong!). The call clobbers lr. // For now, I've dealt with this by ensuring that we never allocate to lr. It
--- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -1691,17 +1691,17 @@ class MOZ_STACK_CLASS ModuleValidator bool addStandardLibrarySimdOpName(const char* name, SimdOperation op) { JSAtom* atom = Atomize(cx_, name, strlen(name)); if (!atom) return false; return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op); } bool newSig(Sig&& sig, uint32_t* sigIndex) { *sigIndex = 0; - if (mg_.numSigs() >= MaxSigs) + if (mg_.numSigs() >= AsmJSMaxTypes) return failCurrentOffset("too many signatures"); *sigIndex = mg_.numSigs(); mg_.initSig(*sigIndex, Move(sig)); return true; } bool declareSig(Sig&& sig, uint32_t* sigIndex) { SigMap::AddPtr p = sigMap_.lookupForAdd(sig); @@ -1838,21 +1838,21 @@ class MOZ_STACK_CLASS ModuleValidator } CompileArgs args; if (!args.initFromContext(cx_, Move(scriptedCaller))) return false; auto env = MakeUnique<ModuleEnvironment>(ModuleKind::AsmJS); if (!env || - !env->sigs.resize(MaxSigs) || - !env->funcSigs.resize(MaxFuncs) || + !env->sigs.resize(AsmJSMaxTypes) || + !env->funcSigs.resize(AsmJSMaxFuncs) || !env->funcImportGlobalDataOffsets.resize(AsmJSMaxImports) || - !env->tables.resize(MaxTables) || - !env->asmJSSigToTableIndex.resize(MaxSigs)) + !env->tables.resize(AsmJSMaxTables) || + !env->asmJSSigToTableIndex.resize(AsmJSMaxTypes)) { return false; } env->minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0); if (!mg_.init(Move(env), args, asmJSMetadata_.get())) return false; @@ -2151,32 +2151,32 @@ class MOZ_STACK_CLASS ModuleValidator func.srcBegin() - asmJSMetadata_->srcStart, func.srcEnd() - asmJSMetadata_->srcStart); } bool addFunction(PropertyName* name, uint32_t firstUse, Sig&& sig, Func** func) { uint32_t sigIndex; if (!declareSig(Move(sig), &sigIndex)) return false; uint32_t funcIndex = AsmJSFirstDefFuncIndex + numFunctions(); - if (funcIndex >= MaxFuncs) + if (funcIndex >= AsmJSMaxFuncs) return failCurrentOffset("too many functions"); mg_.initFuncSig(funcIndex, sigIndex); Global* global = validationLifo_.new_<Global>(Global::Function); if (!global) return false; global->u.funcIndex_ = funcIndex; if (!globalMap_.putNew(name, global)) return false; *func = validationLifo_.new_<Func>(name, firstUse, funcIndex); return *func && functions_.append(*func); } bool declareFuncPtrTable(Sig&& sig, PropertyName* name, uint32_t firstUse, uint32_t mask, uint32_t* index) { - if (mask > MaxTableElems) + if (mask > MaxTableLength) return failCurrentOffset("function pointer table too big"); uint32_t sigIndex; if (!newSig(Move(sig), &sigIndex)) return false; if (!mg_.initSigTableLength(sigIndex, mask + 1)) return false; Global* global = validationLifo_.new_<Global>(Global::FuncPtrTable); if (!global)
--- a/js/src/wasm/WasmBinaryConstants.h +++ b/js/src/wasm/WasmBinaryConstants.h @@ -435,12 +435,51 @@ enum class Op // or WebAssembly is used. enum class Telemetry { ASMJS = 0, WASM = 1 }; +// Static offsets into the global data of every module that is compiled. + +static const unsigned NaN64GlobalDataOffset = 0; +static const unsigned NaN32GlobalDataOffset = NaN64GlobalDataOffset + sizeof(double); +static const unsigned InitialGlobalDataBytes = NaN32GlobalDataOffset + sizeof(float); + +// These limits are agreed upon with other engines for consistency. + +static const unsigned MaxTypes = 1000000; +static const unsigned MaxFuncs = 1000000; +static const unsigned MaxImports = 100000; +static const unsigned MaxExports = 100000; +static const unsigned MaxGlobals = 1000000; +static const unsigned MaxDataSegments = 100000; +static const unsigned MaxElemSegments = 10000000; +static const unsigned MaxTableLength = 10000000; +static const unsigned MaxStringBytes = 100000; +static const unsigned MaxLocals = 50000; +static const unsigned MaxParams = 1000; +static const unsigned MaxBrTableElems = 1000000; +static const unsigned MaxModuleBytes = 1024 * 1024 * 1024; +static const unsigned MaxFunctionBytes = 128 * 1024; + +// To be able to assign function indices during compilation while the number of +// imports is still unknown, asm.js sets a maximum number of imports so it can +// immediately start handing out function indices starting at the maximum + 1. +// this means that there is a "hole" between the last import and the first +// definition, but that's fine. + +static const unsigned AsmJSMaxTypes = 4 * 1024; +static const unsigned AsmJSMaxFuncs = 512 * 1024; +static const unsigned AsmJSMaxImports = 4 * 1024; +static const unsigned AsmJSMaxTables = 4 * 1024; +static const unsigned AsmJSFirstDefFuncIndex = AsmJSMaxImports + 1; + +static_assert(AsmJSMaxTypes <= MaxTypes, "conservative"); +static_assert(AsmJSMaxImports <= MaxImports, "conservative"); +static_assert(AsmJSFirstDefFuncIndex < MaxFuncs, "conservative"); + } // namespace wasm } // namespace js #endif // wasm_binary_h
--- a/js/src/wasm/WasmGenerator.cpp +++ b/js/src/wasm/WasmGenerator.cpp @@ -105,19 +105,19 @@ ModuleGenerator::initAsmJS(Metadata* asm metadata_ = asmJSMetadata; MOZ_ASSERT(isAsmJS()); // For asm.js, the Vectors in ModuleEnvironment are max-sized reservations // and will be initialized in a linear order via init* functions as the // module is generated. - MOZ_ASSERT(env_->sigs.length() == MaxSigs); - MOZ_ASSERT(env_->tables.length() == MaxTables); - MOZ_ASSERT(env_->asmJSSigToTableIndex.length() == MaxSigs); + MOZ_ASSERT(env_->sigs.length() == AsmJSMaxTypes); + MOZ_ASSERT(env_->tables.length() == AsmJSMaxTables); + MOZ_ASSERT(env_->asmJSSigToTableIndex.length() == AsmJSMaxTypes); return true; } bool ModuleGenerator::initWasm() { MOZ_ASSERT(!env_->isAsmJS()); @@ -1008,17 +1008,17 @@ ModuleGenerator::finishFuncDefs() return true; } bool ModuleGenerator::initSigTableLength(uint32_t sigIndex, uint32_t length) { MOZ_ASSERT(isAsmJS()); MOZ_ASSERT(length != 0); - MOZ_ASSERT(length <= MaxTableElems); + MOZ_ASSERT(length <= MaxTableLength); MOZ_ASSERT(env_->asmJSSigToTableIndex[sigIndex] == 0); env_->asmJSSigToTableIndex[sigIndex] = numTables_; TableDesc& table = env_->tables[numTables_++]; table.kind = TableKind::TypedFunction; table.limits.initial = length; table.limits.maximum = Some(length);
--- a/js/src/wasm/WasmTable.cpp +++ b/js/src/wasm/WasmTable.cpp @@ -145,17 +145,17 @@ Table::grow(uint32_t delta, JSContext* c // onMovingGrowTable does not fire when length == maximum. if (!delta) return length_; uint32_t oldLength = length_; CheckedInt<uint32_t> newLength = oldLength; newLength += delta; - if (!newLength.isValid()) + if (!newLength.isValid() || newLength.value() > MaxTableLength) return -1; if (maximum_ && newLength.value() > maximum_.value()) return -1; MOZ_ASSERT(movingGrowable()); JSRuntime* rt = cx; // Use JSRuntime's MallocProvider to avoid throwing.
--- a/js/src/wasm/WasmTypes.h +++ b/js/src/wasm/WasmTypes.h @@ -1521,43 +1521,12 @@ struct MemoryPatch void offsetBy(uint32_t delta) { offset += delta; } }; WASM_DECLARE_POD_VECTOR(MemoryPatch, MemoryPatchVector) -// Constants: - -static const unsigned NaN64GlobalDataOffset = 0; -static const unsigned NaN32GlobalDataOffset = NaN64GlobalDataOffset + sizeof(double); -static const unsigned InitialGlobalDataBytes = NaN32GlobalDataOffset + sizeof(float); - -static const unsigned MaxSigs = 4 * 1024; -static const unsigned MaxFuncs = 512 * 1024; -static const unsigned MaxGlobals = 4 * 1024; -static const unsigned MaxLocals = 64 * 1024; -static const unsigned MaxImports = 64 * 1024; -static const unsigned MaxExports = 64 * 1024; -static const unsigned MaxTables = 4 * 1024; -static const unsigned MaxTableElems = 1024 * 1024; -static const unsigned MaxDataSegments = 64 * 1024; -static const unsigned MaxElemSegments = 64 * 1024; -static const unsigned MaxArgsPerFunc = 4 * 1024; -static const unsigned MaxBrTableElems = 4 * 1024 * 1024; - -// To be able to assign function indices during compilation while the number of -// imports is still unknown, asm.js sets a maximum number of imports so it can -// immediately start handing out function indices starting at the maximum + 1. -// this means that there is a "hole" between the last import and the first -// definition, but that's fine. - -static const unsigned AsmJSMaxImports = 4 * 1024; -static const unsigned AsmJSFirstDefFuncIndex = AsmJSMaxImports + 1; - -static_assert(AsmJSMaxImports <= MaxImports, "conservative"); -static_assert(AsmJSFirstDefFuncIndex < MaxFuncs, "conservative"); - } // namespace wasm } // namespace js #endif // wasm_types_h
--- a/js/src/wasm/WasmValidate.cpp +++ b/js/src/wasm/WasmValidate.cpp @@ -696,16 +696,19 @@ wasm::ValidateFunctionBody(const ModuleE return f.iter().readFunctionEnd(); } // Section macros. static bool DecodePreamble(Decoder& d) { + if (d.bytesRemain() > MaxModuleBytes) + return d.fail("module too big"); + uint32_t u32; if (!d.readFixedU32(&u32) || u32 != MagicNumber) return d.fail("failed to match magic number"); if (!d.readFixedU32(&u32) || u32 != EncodingVersion) return d.fail("binary version 0x%" PRIx32 " does not match expected version 0x%" PRIx32, u32, EncodingVersion); @@ -720,32 +723,32 @@ DecodeTypeSection(Decoder& d, ModuleEnvi return false; if (sectionStart == Decoder::NotStarted) return true; uint32_t numSigs; if (!d.readVarU32(&numSigs)) return d.fail("expected number of signatures"); - if (numSigs > MaxSigs) + if (numSigs > MaxTypes) return d.fail("too many signatures"); if (!env->sigs.resize(numSigs)) return false; for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) { uint32_t form; if (!d.readVarU32(&form) || form != uint32_t(TypeCode::Func)) return d.fail("expected function form"); uint32_t numArgs; if (!d.readVarU32(&numArgs)) return d.fail("bad number of function args"); - if (numArgs > MaxArgsPerFunc) + if (numArgs > MaxParams) return d.fail("too many arguments in signature"); ValTypeVector args; if (!args.resize(numArgs)) return false; for (uint32_t i = 0; i < numArgs; i++) { if (!DecodeValType(d, ModuleKind::Wasm, &args[i])) @@ -780,16 +783,19 @@ DecodeTypeSection(Decoder& d, ModuleEnvi static UniqueChars DecodeName(Decoder& d) { uint32_t numBytes; if (!d.readVarU32(&numBytes)) return nullptr; + if (numBytes > MaxStringBytes) + return nullptr; + const uint8_t* bytes; if (!d.readBytes(numBytes, &bytes)) return nullptr; UniqueChars name(js_pod_malloc<char>(numBytes + 1)); if (!name) return nullptr; @@ -850,17 +856,17 @@ DecodeTableLimits(Decoder& d, TableDescV if (elementType != uint32_t(TypeCode::AnyFunc)) return d.fail("expected 'anyfunc' element type"); Limits limits; if (!DecodeLimits(d, &limits)) return false; - if (limits.initial > MaxTableElems) + if (limits.initial > MaxTableLength) return d.fail("too many table elements"); if (tables->length()) return d.fail("already have default table"); return tables->emplaceBack(TableKind::AnyFunction, limits); } @@ -954,16 +960,18 @@ DecodeImport(Decoder& d, ModuleEnvironme switch (importKind) { case DefinitionKind::Function: { uint32_t sigIndex; if (!DecodeSignatureIndex(d, env->sigs, &sigIndex)) return false; if (!env->funcSigs.append(&env->sigs[sigIndex])) return false; + if (env->funcSigs.length() > MaxFuncs) + return d.fail("too many functions"); break; } case DefinitionKind::Table: { if (!DecodeTableLimits(d, &env->tables)) return false; env->tables.back().external = true; break; } @@ -976,16 +984,18 @@ DecodeImport(Decoder& d, ModuleEnvironme ValType type; bool isMutable; if (!DecodeGlobalType(d, &type, &isMutable)) return false; if (!GlobalIsJSCompatible(d, type, isMutable)) return false; if (!env->globals.append(GlobalDesc(type, isMutable, env->globals.length()))) return false; + if (env->globals.length() > MaxGlobals) + return d.fail("too many globals"); break; } default: return d.fail("unsupported import kind"); } return env->imports.emplaceBack(Move(moduleName), Move(funcName), importKind); } @@ -1387,16 +1397,19 @@ DecodeElemSection(Decoder& d, ModuleEnvi InitExpr offset; if (!DecodeInitializerExpression(d, env->globals, ValType::I32, &offset)) return false; uint32_t numElems; if (!d.readVarU32(&numElems)) return d.fail("expected segment size"); + if (numElems > MaxTableLength) + return d.fail("too many table elements"); + Uint32Vector elemFuncIndices; if (!elemFuncIndices.resize(numElems)) return false; for (uint32_t i = 0; i < numElems; i++) { if (!d.readVarU32(&elemFuncIndices[i])) return d.fail("failed to read element function index"); if (elemFuncIndices[i] >= env->numFuncs()) @@ -1453,16 +1466,19 @@ wasm::DecodeModuleEnvironment(Decoder& d static bool DecodeFunctionBody(Decoder& d, const ModuleEnvironment& env, uint32_t funcIndex) { uint32_t bodySize; if (!d.readVarU32(&bodySize)) return d.fail("expected number of function body bytes"); + if (bodySize > MaxFunctionBytes) + return d.fail("function body too big"); + if (d.bytesRemain() < bodySize) return d.fail("function body length too big"); const uint8_t* bodyBegin = d.currentPosition(); if (!ValidateFunctionBody(env, funcIndex, d)) return false; @@ -1570,33 +1586,41 @@ MaybeDecodeNameSectionBody(Decoder& d, M NameInBytecodeVector funcNames; if (!funcNames.resize(numFuncNames)) return; for (uint32_t i = 0; i < numFuncNames; i++) { uint32_t numBytes; if (!d.readVarU32(&numBytes)) return; + if (numBytes > MaxStringLength) + return; NameInBytecode name; name.offset = d.currentOffset(); name.length = numBytes; funcNames[i] = name; if (!d.readBytes(numBytes)) return; // Skip local names for a function. uint32_t numLocals; if (!d.readVarU32(&numLocals)) return; + if (numLocals > MaxLocals) + return; + for (uint32_t j = 0; j < numLocals; j++) { uint32_t numBytes; if (!d.readVarU32(&numBytes)) return; + if (numBytes > MaxStringLength) + return; + if (!d.readBytes(numBytes)) return; } } env->funcNames = Move(funcNames); }