// Bounds checks always compare the base of the memory access with the bounds // check limit. If the memory access is unaligned, this means that, even if the // bounds check succeeds, a few bytes of the access can extend past the end of // memory. To guard against this, extra space is included in the guard region to // catch the overflow. MaxMemoryAccessSize is a conservative approximation of // the maximum guard space needed to catch all unaligned overflows. // // Also see "Linear memory addresses and bounds checking" above.
// All plausible targets must be able to do at least IEEE754 double // loads/stores, hence the lower limit of 8. Some Intel processors support // AVX-512 loads/stores, hence the upper limit of 64.
static_assert(MaxMemoryAccessSize >= 8, "MaxMemoryAccessSize too low");
static_assert(MaxMemoryAccessSize <= 64, "MaxMemoryAccessSize too high");
static_assert((MaxMemoryAccessSize & (MaxMemoryAccessSize - 1)) == 0, "MaxMemoryAccessSize is not a power of two");
#ifdef WASM_SUPPORTS_HUGE_MEMORY
static_assert(MaxMemoryAccessSize <= HugeUnalignedGuardPage, "rounded up to static page size");
static_assert(HugeOffsetGuardLimit < UINT32_MAX, "checking for overflow against OffsetGuardLimit is enough.");
// We have only tested huge memory on x64, arm64 and riscv64. # if !(defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM64) || \ defined(JS_CODEGEN_RISCV64)) # error "Not an expected configuration" # endif
#endif
// On !WASM_SUPPORTS_HUGE_MEMORY platforms: // - To avoid OOM in ArrayBuffer::prepareForAsmJS, asm.js continues to use the // original ArrayBuffer allocation which has no guard region at all. // - For WebAssembly memories, an additional GuardSize is mapped after the // accessible region of the memory to catch folded (base+offset) accesses // where `offset < OffsetGuardLimit` as well as the overflow from unaligned // accesses, as described above for MaxMemoryAccessSize.
wasm::Pages wasm::MaxMemoryPages(AddressType t, PageSize pageSize) { #ifdef JS_64BIT
MOZ_ASSERT_IF(t == AddressType::I64, !IsHugeMemoryEnabled(t, pageSize));
size_t desired = MaxMemoryPagesValidation(t, pageSize);
size_t actual =
ArrayBufferObject::ByteLengthLimit / PageSizeInBytes(pageSize); return wasm::Pages::fromPageCount(std::min(desired, actual), pageSize); #else // On 32-bit systems, the heap limit must be representable in the nonnegative // range of an int32_t, which means the maximum heap size as observed by wasm // code is one wasm page less than 2GB.
MOZ_ASSERT(ArrayBufferObject::ByteLengthLimit >=
INT32_MAX / PageSizeInBytes(pageSize)); return wasm::Pages::fromPageCount(INT32_MAX / PageSizeInBytes(pageSize),
pageSize); #endif
}
if (sourceMaxPages.isSome()) { // There is a specified maximum, clamp it to the implementation limit of // maximum pages
clampedMaxPages =
std::min(*sourceMaxPages, wasm::MaxMemoryPages(t, pageSize));
#ifndef JS_64BIT
static_assert(sizeof(uintptr_t) == 4, "assuming not 64 bit implies 32 bit");
// On 32-bit platforms, prevent applications specifying a large max (like // MaxMemoryPages()) from unintentially OOMing the browser: they just want // "a lot of memory". Maintain the invariant that initialPages <= // clampedMaxPages. staticconst uint64_t OneGib = 1 << 30; const Pages OneGibPages = Pages::fromByteLengthExact(OneGib, pageSize);
Pages clampedPages = std::max(OneGibPages, initialPages);
clampedMaxPages = std::min(clampedPages, clampedMaxPages); #endif
} else { // There is not a specified maximum, fill it in with the implementation // limit of maximum pages
clampedMaxPages = wasm::MaxMemoryPages(t, pageSize);
}
size_t wasm::ComputeMappedSize(wasm::Pages clampedMaxPages) { // Caller is responsible to ensure that clampedMaxPages has been clamped to // implementation limits.
size_t maxSize = clampedMaxPages.byteLength();
// For tiny page sizes, round up the mapped size to a multiple of the // system page size after clamping. #ifdef ENABLE_WASM_CUSTOM_PAGE_SIZES if (clampedMaxPages.pageSize() == wasm::PageSize::Tiny) {
mozilla::CheckedInt<size_t> length(maxSize);
if (length.value() % gc::SystemPageSize() != 0) {
length += ComputeByteAlignment(length.value(), gc::SystemPageSize()); // This should be valid because of previous clamping.
MOZ_RELEASE_ASSERT(length.isValid());
MOZ_ASSERT(length.value() % gc::SystemPageSize() == 0);
maxSize = length.value();
}
MOZ_ASSERT(maxSize % gc::SystemPageSize() == 0);
MOZ_ASSERT(GuardSize % gc::SystemPageSize() == 0); if (clampedMaxPages.pageSize() == PageSize::Standard) {
maxSize += GuardSize;
} else { #ifdef ENABLE_WASM_CUSTOM_PAGE_SIZES // In the case of a tiny page, we omit the guard page size // because we can't use guard pages for tiny page bounds checks.
MOZ_ASSERT(clampedMaxPages.pageSize() == PageSize::Tiny); #else
MOZ_CRASH(); #endif
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.