Diff
Modified: trunk/JSTests/ChangeLog (259645 => 259646)
--- trunk/JSTests/ChangeLog 2020-04-07 17:39:24 UTC (rev 259645)
+++ trunk/JSTests/ChangeLog 2020-04-07 18:04:57 UTC (rev 259646)
@@ -1,5 +1,19 @@
2020-04-07 Yusuke Suzuki <ysuz...@apple.com>
+ [JSC] ScopedArgumentsTable should handle OOM in tolerant manner
+ https://bugs.webkit.org/show_bug.cgi?id=210126
+
+ Reviewed by Mark Lam.
+
+ * stress/scoped-arguments-table-should-be-tolerant-for-oom.js: Added.
+ (canThrow):
+ (bar):
+ (get bar):
+ (foo):
+ (i.canThrow):
+
+2020-04-07 Yusuke Suzuki <ysuz...@apple.com>
+
[JSC] Inlined IC should get right JSGlobalObject
https://bugs.webkit.org/show_bug.cgi?id=210092
Added: trunk/JSTests/stress/scoped-arguments-table-should-be-tolerant-for-oom.js (0 => 259646)
--- trunk/JSTests/stress/scoped-arguments-table-should-be-tolerant-for-oom.js (rev 0)
+++ trunk/JSTests/stress/scoped-arguments-table-should-be-tolerant-for-oom.js 2020-04-07 18:04:57 UTC (rev 259646)
@@ -0,0 +1,43 @@
+//@ skip if $memoryLimited
+//@ slow!
+
+function canThrow(func, errorMessage) {
+ var errorThrown = false;
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ errorThrown = true;
+ error = e;
+ }
+ if (errorThrown && String(error) !== errorMessage)
+ throw new Error(`bad error: ${String(error)}`);
+}
+
+const a0 = [];
+a0.__proto__ = {};
+a0.length = 2**26;
+Object.defineProperty(a0, 0, {get: bar});
+
+function bar() {
+ new Uint8Array(a0);
+}
+
+new Promise(bar);
+
+try {
+ for (let i=0; i<10000; i++) {
+ new Uint8Array(10000);
+ }
+} catch {}
+
+function foo(x, y, z) {
+ delete arguments[0];
+ with (Object) {}
+}
+
+for (let i=0; i<10000; i++) {
+ canThrow(() => {
+ foo(0);
+ }, `Error: Out of memory`);
+}
Modified: trunk/Source/_javascript_Core/ChangeLog (259645 => 259646)
--- trunk/Source/_javascript_Core/ChangeLog 2020-04-07 17:39:24 UTC (rev 259645)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-04-07 18:04:57 UTC (rev 259646)
@@ -1,5 +1,30 @@
2020-04-07 Yusuke Suzuki <ysuz...@apple.com>
+ [JSC] ScopedArgumentsTable should handle OOM in tolerant manner
+ https://bugs.webkit.org/show_bug.cgi?id=210126
+
+ Reviewed by Mark Lam.
+
+ This patch makes ScopedArgumentsTable allocations OOM tolerant to throw OOM error when allocation fails.
+
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ * runtime/CachedTypes.cpp:
+ (JSC::CachedScopedArgumentsTable::decode const):
+ * runtime/ScopedArguments.cpp:
+ (JSC::ScopedArguments::unmapArgument):
+ * runtime/ScopedArgumentsTable.cpp:
+ (JSC::ScopedArgumentsTable::tryClone):
+ (JSC::ScopedArgumentsTable::trySetLength):
+ (JSC::ScopedArgumentsTable::trySet):
+ (JSC::ScopedArgumentsTable::clone): Deleted.
+ (JSC::ScopedArgumentsTable::setLength): Deleted.
+ (JSC::ScopedArgumentsTable::set): Deleted.
+ * runtime/ScopedArgumentsTable.h:
+ * runtime/SymbolTable.h:
+
+2020-04-07 Yusuke Suzuki <ysuz...@apple.com>
+
[JSC] JSWrapperObject should use JSInternalFieldObjectImpl
https://bugs.webkit.org/show_bug.cgi?id=210019
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (259645 => 259646)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2020-04-07 17:39:24 UTC (rev 259645)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2020-04-07 18:04:57 UTC (rev 259646)
@@ -505,7 +505,11 @@
// way we lift the value into the scope.
for (unsigned i = 0; i < parameters.size(); ++i) {
ScopeOffset offset = functionSymbolTable->takeNextScopeOffset(NoLockingNecessary);
- functionSymbolTable->setArgumentOffset(vm, i, offset);
+ bool success = functionSymbolTable->trySetArgumentOffset(vm, i, offset);
+ if (UNLIKELY(!success)) {
+ m_outOfMemoryDuringConstruction = true;
+ return;
+ }
if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i).first)) {
VarOffset varOffset(offset);
SymbolTableEntry entry(varOffset);
Modified: trunk/Source/_javascript_Core/runtime/CachedTypes.cpp (259645 => 259646)
--- trunk/Source/_javascript_Core/runtime/CachedTypes.cpp 2020-04-07 17:39:24 UTC (rev 259645)
+++ trunk/Source/_javascript_Core/runtime/CachedTypes.cpp 2020-04-07 18:04:57 UTC (rev 259646)
@@ -1121,7 +1121,8 @@
ScopedArgumentsTable* decode(Decoder& decoder) const
{
- ScopedArgumentsTable* scopedArgumentsTable = ScopedArgumentsTable::create(decoder.vm(), m_length);
+ ScopedArgumentsTable* scopedArgumentsTable = ScopedArgumentsTable::tryCreate(decoder.vm(), m_length);
+ RELEASE_ASSERT(scopedArgumentsTable); // We crash here. This is unlikely to continue execution if we hit this condition when decoding UnlinkedCodeBlock.
m_arguments.decode(decoder, scopedArgumentsTable->m_arguments.get(m_length), m_length);
return scopedArgumentsTable;
}
Modified: trunk/Source/_javascript_Core/runtime/ScopedArguments.cpp (259645 => 259646)
--- trunk/Source/_javascript_Core/runtime/ScopedArguments.cpp 2020-04-07 17:39:24 UTC (rev 259645)
+++ trunk/Source/_javascript_Core/runtime/ScopedArguments.cpp 2020-04-07 18:04:57 UTC (rev 259646)
@@ -143,11 +143,17 @@
void ScopedArguments::unmapArgument(JSGlobalObject* globalObject, uint32_t i)
{
VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
ASSERT_WITH_SECURITY_IMPLICATION(i < m_totalLength);
unsigned namedLength = m_table->length();
- if (i < namedLength)
- m_table.set(vm, this, m_table->set(vm, i, ScopeOffset()));
- else
+ if (i < namedLength) {
+ auto* maybeCloned = m_table->trySet(vm, i, ScopeOffset());
+ if (UNLIKELY(!maybeCloned)) {
+ throwOutOfMemoryError(globalObject, scope);
+ return;
+ }
+ m_table.set(vm, this, maybeCloned);
+ } else
storage()[i - namedLength].clear();
}
Modified: trunk/Source/_javascript_Core/runtime/ScopedArgumentsTable.cpp (259645 => 259646)
--- trunk/Source/_javascript_Core/runtime/ScopedArgumentsTable.cpp 2020-04-07 17:39:24 UTC (rev 259645)
+++ trunk/Source/_javascript_Core/runtime/ScopedArgumentsTable.cpp 2020-04-07 18:04:57 UTC (rev 259646)
@@ -56,14 +56,6 @@
return result;
}
-ScopedArgumentsTable* ScopedArgumentsTable::create(VM& vm, uint32_t length)
-{
- ScopedArgumentsTable* result = create(vm);
- result->m_length = length;
- result->m_arguments = ArgumentsPtr::create(length);
- return result;
-}
-
ScopedArgumentsTable* ScopedArgumentsTable::tryCreate(VM& vm, uint32_t length)
{
void* buffer = tryAllocateCell<ScopedArgumentsTable>(vm.heap);
@@ -79,18 +71,22 @@
return result;
}
-ScopedArgumentsTable* ScopedArgumentsTable::clone(VM& vm)
+ScopedArgumentsTable* ScopedArgumentsTable::tryClone(VM& vm)
{
- ScopedArgumentsTable* result = create(vm, m_length);
+ ScopedArgumentsTable* result = tryCreate(vm, m_length);
+ if (UNLIKELY(!result))
+ return nullptr;
for (unsigned i = m_length; i--;)
result->at(i) = this->at(i);
return result;
}
-ScopedArgumentsTable* ScopedArgumentsTable::setLength(VM& vm, uint32_t newLength)
+ScopedArgumentsTable* ScopedArgumentsTable::trySetLength(VM& vm, uint32_t newLength)
{
if (LIKELY(!m_locked)) {
- ArgumentsPtr newArguments = ArgumentsPtr::create(newLength, newLength);
+ ArgumentsPtr newArguments = ArgumentsPtr::tryCreate(newLength, newLength);
+ if (UNLIKELY(!newArguments))
+ return nullptr;
for (unsigned i = std::min(m_length, newLength); i--;)
newArguments.at(i, newLength) = this->at(i);
m_length = newLength;
@@ -98,7 +94,9 @@
return this;
}
- ScopedArgumentsTable* result = create(vm, newLength);
+ ScopedArgumentsTable* result = tryCreate(vm, newLength);
+ if (UNLIKELY(!result))
+ return nullptr;
for (unsigned i = std::min(m_length, newLength); i--;)
result->at(i) = this->at(i);
return result;
@@ -106,12 +104,14 @@
static_assert(std::is_trivially_destructible<ScopeOffset>::value, "");
-ScopedArgumentsTable* ScopedArgumentsTable::set(VM& vm, uint32_t i, ScopeOffset value)
+ScopedArgumentsTable* ScopedArgumentsTable::trySet(VM& vm, uint32_t i, ScopeOffset value)
{
ScopedArgumentsTable* result;
- if (UNLIKELY(m_locked))
- result = clone(vm);
- else
+ if (UNLIKELY(m_locked)) {
+ result = tryClone(vm);
+ if (UNLIKELY(!result))
+ return nullptr;
+ } else
result = this;
result->at(i) = value;
return result;
Modified: trunk/Source/_javascript_Core/runtime/ScopedArgumentsTable.h (259645 => 259646)
--- trunk/Source/_javascript_Core/runtime/ScopedArgumentsTable.h 2020-04-07 17:39:24 UTC (rev 259645)
+++ trunk/Source/_javascript_Core/runtime/ScopedArgumentsTable.h 2020-04-07 18:04:57 UTC (rev 259646)
@@ -59,15 +59,12 @@
public:
static ScopedArgumentsTable* create(VM&);
- static ScopedArgumentsTable* create(VM&, uint32_t length);
static ScopedArgumentsTable* tryCreate(VM&, uint32_t length);
static void destroy(JSCell*);
- ScopedArgumentsTable* clone(VM&);
-
uint32_t length() const { return m_length; }
- ScopedArgumentsTable* setLength(VM&, uint32_t newLength);
+ ScopedArgumentsTable* trySetLength(VM&, uint32_t newLength);
ScopeOffset get(uint32_t i) const { return at(i); }
@@ -76,7 +73,7 @@
m_locked = true;
}
- ScopedArgumentsTable* set(VM&, uint32_t index, ScopeOffset);
+ ScopedArgumentsTable* trySet(VM&, uint32_t index, ScopeOffset);
DECLARE_INFO;
@@ -88,6 +85,8 @@
typedef CagedUniquePtr<Gigacage::Primitive, ScopeOffset> ArgumentsPtr;
private:
+ ScopedArgumentsTable* tryClone(VM&);
+
ScopeOffset& at(uint32_t i) const
{
ASSERT_WITH_SECURITY_IMPLICATION(i < m_length);
Modified: trunk/Source/_javascript_Core/runtime/SymbolTable.h (259645 => 259646)
--- trunk/Source/_javascript_Core/runtime/SymbolTable.h 2020-04-07 17:39:24 UTC (rev 259645)
+++ trunk/Source/_javascript_Core/runtime/SymbolTable.h 2020-04-07 18:04:57 UTC (rev 259646)
@@ -642,8 +642,12 @@
if (UNLIKELY(!table))
return false;
m_arguments.set(vm, this, table);
- } else
- m_arguments.set(vm, this, m_arguments->setLength(vm, length));
+ } else {
+ ScopedArgumentsTable* table = m_arguments->trySetLength(vm, length);
+ if (UNLIKELY(!table))
+ return false;
+ m_arguments.set(vm, this, table);
+ }
return true;
}
@@ -653,10 +657,14 @@
return m_arguments->get(i);
}
- void setArgumentOffset(VM& vm, uint32_t i, ScopeOffset offset)
+ bool trySetArgumentOffset(VM& vm, uint32_t i, ScopeOffset offset)
{
ASSERT_WITH_SECURITY_IMPLICATION(m_arguments);
- m_arguments.set(vm, this, m_arguments->set(vm, i, offset));
+ auto* maybeCloned = m_arguments->trySet(vm, i, offset);
+ if (!maybeCloned)
+ return false;
+ m_arguments.set(vm, this, maybeCloned);
+ return true;
}
ScopedArgumentsTable* arguments() const