Diff
Modified: trunk/JSTests/ChangeLog (275596 => 275597)
--- trunk/JSTests/ChangeLog 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/JSTests/ChangeLog 2021-04-07 09:28:49 UTC (rev 275597)
@@ -1,3 +1,20 @@
+2021-04-06 Yusuke Suzuki <[email protected]>
+
+ [JSC] WasmMemory caging should care about nullptr
+ https://bugs.webkit.org/show_bug.cgi?id=224268
+ <rdar://problem/74654838>
+
+ Reviewed by Mark Lam.
+
+ * wasm/stress/4g-memory-cage.js: Added.
+ (async test):
+ * wasm/stress/more-than-4g-offset-access-oom.js: Added.
+ (async test):
+ * wasm/stress/null-memory-cage-explicit.js: Added.
+ (async test):
+ * wasm/stress/null-memory-cage.js: Added.
+ (async test):
+
2021-04-06 Alexey Shvayka <[email protected]>
Symbol and BigInt wrapper objects should perform OrdinaryToPrimitive
Added: trunk/JSTests/wasm/stress/4g-memory-cage.js (0 => 275597)
--- trunk/JSTests/wasm/stress/4g-memory-cage.js (rev 0)
+++ trunk/JSTests/wasm/stress/4g-memory-cage.js 2021-04-07 09:28:49 UTC (rev 275597)
@@ -0,0 +1,18 @@
+import { instantiate } from "../wabt-wrapper.js";
+import * as assert from "../assert.js";
+
+let wat = `
+(module
+ (memory $mem0 1)
+ (func (export "test") (param $sz i32) (result i32)
+ (local.get $sz)
+ )
+)
+`;
+async function test() {
+ const instance = await instantiate(wat, {}, {reference_types: true});
+ const {test} = instance.exports;
+ assert.eq(test(42), 42);
+}
+
+assert.asyncTest(test());
Added: trunk/JSTests/wasm/stress/more-than-4g-offset-access-oom.js (0 => 275597)
--- trunk/JSTests/wasm/stress/more-than-4g-offset-access-oom.js (rev 0)
+++ trunk/JSTests/wasm/stress/more-than-4g-offset-access-oom.js 2021-04-07 09:28:49 UTC (rev 275597)
@@ -0,0 +1,22 @@
+import { instantiate } from "../wabt-wrapper.js";
+import * as assert from "../assert.js";
+
+let wat = `
+(module
+ (memory $mem0 1)
+ (func (export "test") (param $sz i32) (result i32)
+ (i32.load offset=0xff00 (local.get $sz))
+ )
+)
+`;
+async function test() {
+ const instance = await instantiate(wat, {}, {reference_types: true});
+ const {test} = instance.exports;
+ // In fast-memory configuration, this pass bound-checking (expected).
+ // And then, accessing to redzone, and this causes fault. And signal handler throws an error correctly.
+ assert.throws(() => {
+ test(0xffffffff);
+ }, WebAssembly.RuntimeError, `Out of bounds memory access`);
+}
+
+assert.asyncTest(test());
Added: trunk/JSTests/wasm/stress/null-memory-cage-explicit.js (0 => 275597)
--- trunk/JSTests/wasm/stress/null-memory-cage-explicit.js (rev 0)
+++ trunk/JSTests/wasm/stress/null-memory-cage-explicit.js 2021-04-07 09:28:49 UTC (rev 275597)
@@ -0,0 +1,18 @@
+import { instantiate } from "../wabt-wrapper.js";
+import * as assert from "../assert.js";
+
+let wat = `
+(module
+ (memory 0 0)
+ (func (export "test") (param $sz i32) (result i32)
+ (memory.grow (local.get $sz))
+ )
+)
+`;
+async function test() {
+ const instance = await instantiate(wat, {}, {reference_types: true});
+ const {test} = instance.exports;
+ assert.eq(test(42), -1);
+}
+
+assert.asyncTest(test());
Added: trunk/JSTests/wasm/stress/null-memory-cage.js (0 => 275597)
--- trunk/JSTests/wasm/stress/null-memory-cage.js (rev 0)
+++ trunk/JSTests/wasm/stress/null-memory-cage.js 2021-04-07 09:28:49 UTC (rev 275597)
@@ -0,0 +1,17 @@
+import { instantiate } from "../wabt-wrapper.js";
+import * as assert from "../assert.js";
+
+let wat = `
+(module
+ (func (export "test") (param $sz i32) (result i32)
+ (local.get $sz)
+ )
+)
+`;
+async function test() {
+ const instance = await instantiate(wat, {}, {reference_types: true});
+ const {test} = instance.exports;
+ assert.eq(test(42), 42);
+}
+
+assert.asyncTest(test());
Modified: trunk/Source/_javascript_Core/ChangeLog (275596 => 275597)
--- trunk/Source/_javascript_Core/ChangeLog 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-04-07 09:28:49 UTC (rev 275597)
@@ -1,5 +1,43 @@
2021-04-06 Yusuke Suzuki <[email protected]>
+ [JSC] WasmMemory caging should care about nullptr
+ https://bugs.webkit.org/show_bug.cgi?id=224268
+ <rdar://problem/74654838>
+
+ Reviewed by Mark Lam.
+
+ 1. Fix Wasm::MemoryHandle::boundsCheckingSize. We should just return m_mappedCapacity here since UINT32_MAX is not 4GB.
+ This checking size can include redzone for fast-memory, but this is OK: bounds-check pass in LLInt (in upper tiers, we
+ do not use bounds-check for fast-memory), and access to redzone, then fault occurs and signal handler can make it error
+ since signal handler is checking whether the access is within Memory::fastMappedBytes which includes redzone.
+ 2. Fix caging of wasm memory-base pointer in LLInt. We should use pointer sized length since it can be larger than 4GB.
+ And we should handle nullptr case correctly: Wasm::MemoryHandle's memory can be nullptr when mapped size is zero.
+ caging needs to handle this case as we do in CagedPtr::getMayBeNull.
+
+ * assembler/MacroAssemblerARM64E.h:
+ (JSC::MacroAssemblerARM64E::untagArrayPtrLength32):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::cageTypedArrayStorage):
+ * llint/LowLevelInterpreter64.asm:
+ * llint/WebAssembly.asm:
+ * offlineasm/arm64e.rb:
+ * offlineasm/ast.rb:
+ * offlineasm/instructions.rb:
+ * runtime/CagedBarrierPtr.h:
+ (JSC::CagedBarrierPtr::CagedBarrierPtr):
+ (JSC::CagedBarrierPtr::set):
+ (JSC::CagedBarrierPtr::get const):
+ (JSC::CagedBarrierPtr::getMayBeNull const):
+ (JSC::CagedBarrierPtr::at const):
+ (JSC::CagedBarrierPtr::setWithoutBarrier):
+ * wasm/WasmInstance.h:
+ (JSC::Wasm::Instance::updateCachedMemory):
+ * wasm/WasmMemory.cpp:
+ (JSC::Wasm::MemoryHandle::MemoryHandle):
+ * wasm/WasmMemory.h:
+
+2021-04-06 Yusuke Suzuki <[email protected]>
+
[JSC] Use FixedVector more in JSC
https://bugs.webkit.org/show_bug.cgi?id=224255
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64E.h (275596 => 275597)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64E.h 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64E.h 2021-04-07 09:28:49 UTC (rev 275597)
@@ -128,7 +128,7 @@
}
}
- ALWAYS_INLINE void untagArrayPtr(Address length, RegisterID target, bool validateAuth)
+ ALWAYS_INLINE void untagArrayPtrLength32(Address length, RegisterID target, bool validateAuth)
{
auto lengthGPR = getCachedDataTempRegisterIDAndInvalidate();
load32(length, lengthGPR);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (275596 => 275597)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-04-07 09:28:49 UTC (rev 275597)
@@ -7485,7 +7485,7 @@
{
auto untagArrayPtr = [&]() {
#if CPU(ARM64E)
- m_jit.untagArrayPtr(MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfLength()), storageReg, validateAuth);
+ m_jit.untagArrayPtrLength32(MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfLength()), storageReg, validateAuth);
#else
UNUSED_PARAM(validateAuth);
UNUSED_PARAM(baseReg);
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (275596 => 275597)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2021-04-07 09:28:49 UTC (rev 275597)
@@ -497,6 +497,31 @@
end
end
+macro cagedPrimitiveMayBeNull(ptr, length, scratch, scratch2)
+ if ARM64E
+ const source = scratch2
+ move ptr, scratch2
+ removeArrayPtrTag scratch2
+ btpz scratch2, .nullCase
+ move ptr, scratch2
+ else
+ # Note that we may produce non-nullptr for nullptr in non-ARM64E architecture since we add Gigacage offset.
+ # But this behavior is aligned to AssemblyHelpers::{cageConditionallyAndUntag,cageWithoutUntagging}, FTL implementation of caging etc.
+ const source = ptr
+ end
+ if GIGACAGE_ENABLED
+ cagePrimitive(GigacageConfig + Gigacage::Config::basePtrs + GigacagePrimitiveBasePtrOffset, constexpr Gigacage::primitiveGigacageMask, source, scratch)
+ if ARM64E
+ const numberOfPACBits = constexpr MacroAssembler::numberOfPACBits
+ bfiq scratch2, 0, 64 - numberOfPACBits, ptr
+ end
+ end
+ if ARM64E
+ .nullCase:
+ untagArrayPtr length, ptr
+ end
+end
+
macro loadCagedJSValue(source, dest, scratchOrLength)
loadp source, dest
if GIGACAGE_ENABLED
Modified: trunk/Source/_javascript_Core/llint/WebAssembly.asm (275596 => 275597)
--- trunk/Source/_javascript_Core/llint/WebAssembly.asm 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/llint/WebAssembly.asm 2021-04-07 09:28:49 UTC (rev 275597)
@@ -246,8 +246,8 @@
macro reloadMemoryRegistersFromInstance(instance, scratch1, scratch2)
loadp Wasm::Instance::m_cachedMemory[instance], memoryBase
- loadi Wasm::Instance::m_cachedBoundsCheckingSize[instance], boundsCheckingSize
- cagedPrimitive(memoryBase, boundsCheckingSize, scratch1, scratch2)
+ loadp Wasm::Instance::m_cachedBoundsCheckingSize[instance], boundsCheckingSize
+ cagedPrimitiveMayBeNull(memoryBase, boundsCheckingSize, scratch1, scratch2) # If boundsCheckingSize is 0, pointer can be a nullptr.
end
macro throwException(exception)
Modified: trunk/Source/_javascript_Core/offlineasm/arm64e.rb (275596 => 275597)
--- trunk/Source/_javascript_Core/offlineasm/arm64e.rb 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/offlineasm/arm64e.rb 2021-04-07 09:28:49 UTC (rev 275597)
@@ -146,6 +146,9 @@
when "untagArrayPtr"
raise if operands.size != 2 or not operands.each { |operand| operand.is_a? RegisterID or operand.is_a? Tmp }
emitARM64("autdb ", operands, :ptr)
+ when "removeArrayPtrTag"
+ raise unless operands[0].is_a? RegisterID
+ emitARM64Unflipped("xpacd ", operands, :ptr)
when "ret"
$asm.puts "retab"
else
Modified: trunk/Source/_javascript_Core/offlineasm/ast.rb (275596 => 275597)
--- trunk/Source/_javascript_Core/offlineasm/ast.rb 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/offlineasm/ast.rb 2021-04-07 09:28:49 UTC (rev 275597)
@@ -945,7 +945,7 @@
$asm.putGlobalAnnotation
when "emit"
$asm.puts "#{operands[0].dump}"
- when "tagCodePtr", "tagReturnAddress", "untagReturnAddress", "removeCodePtrTag", "untagArrayPtr"
+ when "tagCodePtr", "tagReturnAddress", "untagReturnAddress", "removeCodePtrTag", "untagArrayPtr", "removeArrayPtrTag"
else
raise "Unhandled opcode #{opcode} at #{codeOriginString}"
end
Modified: trunk/Source/_javascript_Core/offlineasm/instructions.rb (275596 => 275597)
--- trunk/Source/_javascript_Core/offlineasm/instructions.rb 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/offlineasm/instructions.rb 2021-04-07 09:28:49 UTC (rev 275597)
@@ -307,7 +307,8 @@
"tagReturnAddress",
"untagReturnAddress",
"removeCodePtrTag",
- "untagArrayPtr",
+ "untagArrayPtr",
+ "removeArrayPtrTag",
"tzcnti",
"tzcntq",
"lzcnti",
Modified: trunk/Source/_javascript_Core/runtime/CagedBarrierPtr.h (275596 => 275597)
--- trunk/Source/_javascript_Core/runtime/CagedBarrierPtr.h 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/runtime/CagedBarrierPtr.h 2021-04-07 09:28:49 UTC (rev 275597)
@@ -45,7 +45,7 @@
CagedBarrierPtr() = default;
template<typename U>
- CagedBarrierPtr(VM& vm, JSCell* cell, U&& value, unsigned size)
+ CagedBarrierPtr(VM& vm, JSCell* cell, U&& value, size_t size)
{
m_barrier.set(vm, cell, CagedType(std::forward<U>(value), size));
}
@@ -53,19 +53,19 @@
void clear() { m_barrier.clear(); }
template<typename U>
- void set(VM& vm, JSCell* cell, U&& value, unsigned size)
+ void set(VM& vm, JSCell* cell, U&& value, size_t size)
{
m_barrier.set(vm, cell, CagedType(std::forward<U>(value), size));
}
- T* get(unsigned size) const { return m_barrier.get().get(size); }
- T* getMayBeNull(unsigned size) const { return m_barrier.get().getMayBeNull(size); }
+ T* get(size_t size) const { return m_barrier.get().get(size); }
+ T* getMayBeNull(size_t size) const { return m_barrier.get().getMayBeNull(size); }
T* getUnsafe() const { return m_barrier.get().getUnsafe(); }
// We need the template here so that the type of U is deduced at usage time rather than class time. U should always be T.
template<typename U = T>
typename std::enable_if<!std::is_same<void, U>::value, T>::type&
- /* T& */ at(unsigned index, unsigned size) const { return get(size)[index]; }
+ /* T& */ at(size_t index, size_t size) const { return get(size)[index]; }
bool operator==(const CagedBarrierPtr& other) const
{
@@ -83,7 +83,7 @@
}
template<typename U>
- void setWithoutBarrier(U&& value, unsigned size) { m_barrier.setWithoutBarrier(CagedType(std::forward<U>(value), size)); }
+ void setWithoutBarrier(U&& value, size_t size) { m_barrier.setWithoutBarrier(CagedType(std::forward<U>(value), size)); }
T* rawBits() const
{
Modified: trunk/Source/_javascript_Core/wasm/WasmInstance.h (275596 => 275597)
--- trunk/Source/_javascript_Core/wasm/WasmInstance.h 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/wasm/WasmInstance.h 2021-04-07 09:28:49 UTC (rev 275597)
@@ -109,6 +109,7 @@
if (m_memory != nullptr) {
m_cachedMemory = CagedPtr<Gigacage::Primitive, void, tagCagedPtr>(memory()->memory(), memory()->boundsCheckingSize());
m_cachedBoundsCheckingSize = memory()->boundsCheckingSize();
+ ASSERT(memory()->memory() == cachedMemory());
}
}
Modified: trunk/Source/_javascript_Core/wasm/WasmMemory.cpp (275596 => 275597)
--- trunk/Source/_javascript_Core/wasm/WasmMemory.cpp 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/wasm/WasmMemory.cpp 2021-04-07 09:28:49 UTC (rev 275597)
@@ -279,13 +279,13 @@
MemoryHandle::MemoryHandle(void* memory, size_t size, size_t mappedCapacity, PageCount initial, PageCount maximum, MemorySharingMode sharingMode, MemoryMode mode)
- : m_memory(memory, mappedCapacity)
+ : m_sharingMode(sharingMode)
+ , m_mode(mode)
+ , m_memory(memory, mappedCapacity)
, m_size(size)
, m_mappedCapacity(mappedCapacity)
, m_initial(initial)
, m_maximum(maximum)
- , m_sharingMode(sharingMode)
- , m_mode(mode)
{
#if ASSERT_ENABLED
if (sharingMode == MemorySharingMode::Default && mode == MemoryMode::BoundsChecking)
Modified: trunk/Source/_javascript_Core/wasm/WasmMemory.h (275596 => 275597)
--- trunk/Source/_javascript_Core/wasm/WasmMemory.h 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/_javascript_Core/wasm/WasmMemory.h 2021-04-07 09:28:49 UTC (rev 275597)
@@ -61,12 +61,7 @@
void* memory() const;
size_t size() const { return m_size; }
size_t mappedCapacity() const { return m_mappedCapacity; }
- size_t boundsCheckingSize() const
- {
- if (m_mode == MemoryMode::BoundsChecking)
- return m_mappedCapacity;
- return UINT32_MAX;
- }
+ size_t boundsCheckingSize() const { return m_mappedCapacity; }
PageCount initial() const { return m_initial; }
PageCount maximum() const { return m_maximum; }
MemorySharingMode sharingMode() const { return m_sharingMode; }
@@ -81,14 +76,15 @@
private:
using CagedMemory = CagedPtr<Gigacage::Primitive, void, tagCagedPtr>;
+
+ Lock m_lock;
+ MemorySharingMode m_sharingMode { MemorySharingMode::Default };
+ MemoryMode m_mode { MemoryMode::BoundsChecking };
CagedMemory m_memory;
size_t m_size { 0 };
size_t m_mappedCapacity { 0 };
PageCount m_initial;
PageCount m_maximum;
- MemorySharingMode m_sharingMode { MemorySharingMode::Default };
- MemoryMode m_mode { MemoryMode::BoundsChecking };
- Lock m_lock;
};
class Memory final : public RefCounted<Memory> {
Modified: trunk/Source/WTF/ChangeLog (275596 => 275597)
--- trunk/Source/WTF/ChangeLog 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/WTF/ChangeLog 2021-04-07 09:28:49 UTC (rev 275597)
@@ -1,3 +1,24 @@
+2021-04-06 Yusuke Suzuki <[email protected]>
+
+ [JSC] WasmMemory caging should care nullptr
+ https://bugs.webkit.org/show_bug.cgi?id=224268
+ <rdar://problem/74654838>
+
+ Reviewed by Mark Lam.
+
+ Accept size_t since Wasm::Memory's length can be larger than 4GB.
+
+ * wtf/CagedPtr.h:
+ (WTF::CagedPtr::CagedPtr):
+ (WTF::CagedPtr::get const):
+ (WTF::CagedPtr::getMayBeNull const):
+ (WTF::CagedPtr::at const):
+ (WTF::CagedPtr::recage):
+ * wtf/CagedUniquePtr.h:
+ (WTF::CagedUniquePtr::CagedUniquePtr):
+ (WTF::CagedUniquePtr::create):
+ (WTF::CagedUniquePtr::tryCreate):
+
2021-04-06 Alex Christensen <[email protected]>
Add U+0581 and U+0585 to list of Armenian characters that look like Latin characters
Modified: trunk/Source/WTF/wtf/CagedPtr.h (275596 => 275597)
--- trunk/Source/WTF/wtf/CagedPtr.h 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/WTF/wtf/CagedPtr.h 2021-04-07 09:28:49 UTC (rev 275597)
@@ -47,11 +47,11 @@
: m_ptr(shouldTag ? tagArrayPtr<T>(nullptr, 0) : nullptr)
{ }
- CagedPtr(T* ptr, unsigned size)
+ CagedPtr(T* ptr, size_t size)
: m_ptr(shouldTag ? tagArrayPtr(ptr, size) : ptr)
{ }
- T* get(unsigned size) const
+ T* get(size_t size) const
{
ASSERT(m_ptr);
T* ptr = PtrTraits::unwrap(m_ptr);
@@ -60,7 +60,7 @@
return untaggedPtr;
}
- T* getMayBeNull(unsigned size) const
+ T* getMayBeNull(size_t size) const
{
T* ptr = PtrTraits::unwrap(m_ptr);
if (!removeArrayPtrTag(ptr))
@@ -80,9 +80,9 @@
// We need the template here so that the type of U is deduced at usage time rather than class time. U should always be T.
template<typename U = T>
typename std::enable_if<!std::is_same<void, U>::value, T>::type&
- /* T& */ at(unsigned index, unsigned size) const { return get(size)[index]; }
+ /* T& */ at(size_t index, size_t size) const { return get(size)[index]; }
- void recage(unsigned oldSize, unsigned newSize)
+ void recage(size_t oldSize, size_t newSize)
{
auto ptr = get(oldSize);
ASSERT(ptr == getUnsafe());
Modified: trunk/Source/WTF/wtf/CagedUniquePtr.h (275596 => 275597)
--- trunk/Source/WTF/wtf/CagedUniquePtr.h 2021-04-07 09:10:11 UTC (rev 275596)
+++ trunk/Source/WTF/wtf/CagedUniquePtr.h 2021-04-07 09:28:49 UTC (rev 275597)
@@ -36,7 +36,7 @@
using Base = CagedPtr<kind, T, shouldTag>;
CagedUniquePtr() = default;
- CagedUniquePtr(T* ptr, unsigned size)
+ CagedUniquePtr(T* ptr, size_t size)
: Base(ptr, size)
{ }
@@ -47,7 +47,7 @@
CagedUniquePtr(const CagedUniquePtr&) = delete;
template<typename... Arguments>
- static CagedUniquePtr create(unsigned length, Arguments&&... arguments)
+ static CagedUniquePtr create(size_t length, Arguments&&... arguments)
{
T* result = static_cast<T*>(Gigacage::malloc(kind, sizeof(T) * length));
while (length--)
@@ -56,7 +56,7 @@
}
template<typename... Arguments>
- static CagedUniquePtr tryCreate(unsigned length, Arguments&&... arguments)
+ static CagedUniquePtr tryCreate(size_t length, Arguments&&... arguments)
{
T* result = static_cast<T*>(Gigacage::tryMalloc(kind, sizeof(T) * length));
if (!result)