Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 62 additions & 18 deletions src/jsc/bindings/webcore/SerializedScriptValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,8 +568,13 @@ const uint8_t cryptoKeyOKPOpNameTagMaximumValue = 1;
* Version 11. added support for Blob's memory cost.
* Version 12. added support for agent cluster ID.
* Version 13. added support for ErrorInstance objects.
* Version 14. Date, RegExp, Error, DOMException, CryptoKey, KeyObject, X509Certificate,
* and Bun cloneable types are recorded in the object reference pool on both sides.
*/
[[maybe_unused]] static constexpr unsigned CurrentVersion = 13;
[[maybe_unused]] static constexpr unsigned CurrentVersion = 14;
// Deserializers must not pool the version 14 terminal types for older payloads,
// whose writers never counted them, or the pool indices stop matching the writer's.
[[maybe_unused]] static constexpr unsigned FirstVersionWithPooledTerminals = 14;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
[[maybe_unused]] static constexpr unsigned TerminatorTag = 0xFFFFFFFF;
[[maybe_unused]] static constexpr unsigned StringPoolTag = 0xFFFFFFFE;
[[maybe_unused]] static constexpr unsigned NonIndexPropertiesTag = 0xFFFFFFFD;
Expand Down Expand Up @@ -1589,6 +1594,8 @@ class CloneSerializer : public CloneBase {
void dumpDOMException(JSObject* obj, SerializationReturnCode& code)
{
if (auto* exception = JSDOMException::toWrapped(m_lexicalGlobalObject->vm(), obj)) {
if (!startObjectInternal(obj)) // handle duplicates
return;
write(DOMExceptionTag);
write(exception->message());
write(exception->name());
Expand Down Expand Up @@ -1631,6 +1638,8 @@ class CloneSerializer : public CloneBase {
if (value.isObject()) {
auto* obj = asObject(value);
if (auto* dateObject = dynamicDowncast<DateInstance>(obj)) {
if (!startObjectInternal(dateObject)) // handle duplicates
return true;
write(DateTag);
write(dateObject->internalNumber());
return true;
Expand Down Expand Up @@ -1710,12 +1719,16 @@ class CloneSerializer : public CloneBase {
// return true;
// }
if (auto* regExp = dynamicDowncast<RegExpObject>(obj)) {
if (!startObjectInternal(regExp)) // handle duplicates
return true;
write(RegExpTag);
write(regExp->regExp()->pattern());
write(String::fromLatin1(JSC::Yarr::flagsString(regExp->regExp()->flags()).data()));
return true;
}
if (auto* errorInstance = dynamicDowncast<ErrorInstance>(obj)) {
if (!startObjectInternal(errorInstance)) // handle duplicates
return true;
auto& vm = m_lexicalGlobalObject->vm();
auto errorTypeValue = errorInstance->get(m_lexicalGlobalObject, vm.propertyNames->name);
RETURN_IF_EXCEPTION(scope, false);
Expand Down Expand Up @@ -1850,6 +1863,8 @@ class CloneSerializer : public CloneBase {
code = SerializationReturnCode::DataCloneError;
return true;
}
if (!startObjectInternal(obj)) // handle duplicates
return true;
write(CryptoKeyTag);
Vector<uint8_t> serializedKey;
// Vector<URLKeepingBlobAlive> dummyBlobHandles;
Expand Down Expand Up @@ -2010,12 +2025,12 @@ class CloneSerializer : public CloneBase {
// write bun types
auto _cloneable = StructuredCloneableSerialize::fromJS(value);
if (_cloneable) {
if (!startObjectInternal(obj)) // handle duplicates
return true;
auto cloneable = _cloneable.value();
const bool isTransferCompatible = m_forTransfer == SerializationForCrossProcessTransfer::Yes ? cloneable.isForTransfer : true;
const bool isStorageCompatible = m_forStorage == SerializationForStorage::Yes ? cloneable.isForStorage : true;
if (!isTransferCompatible || !isStorageCompatible) {
if (!startObjectInternal(obj)) // handle duplicates
return true;
write(ObjectTag);
write(TerminatorTag);
return true;
Expand All @@ -2029,10 +2044,12 @@ class CloneSerializer : public CloneBase {
}

if (auto* x509 = dynamicDowncast<Bun::JSX509Certificate>(obj)) {
write(Bun__X509CertificateTag);
if (checkForDuplicate(x509))
return true;
X509* cert = x509->m_x509.get();

// Get the size needed for the DER encoding
// Encode before recording or writing so a DER failure leaves no
// partially written tag and no stale object pool entry behind.
int size = i2d_X509(cert, nullptr);
if (size <= 0)
return false;
Expand All @@ -2041,20 +2058,20 @@ class CloneSerializer : public CloneBase {
der.reserveInitialCapacity(size);
der.grow(size);

// Get pointer to where we should write
unsigned char* der_ptr = der.begin();

// Write the DER encoding
if (i2d_X509(cert, &der_ptr) != size) {
if (i2d_X509(cert, &der_ptr) != size)
return false;
}

recordObject(x509);
write(Bun__X509CertificateTag);
write(der);
Comment thread
robobun marked this conversation as resolved.

return true;
}

if (auto* keyObject = dynamicDowncast<Bun::JSKeyObject>(obj)) {
if (!startObjectInternal(keyObject)) // handle duplicates
return true;
write(Bun__KeyObjectTag);

auto& handle = keyObject->handle();
Expand Down Expand Up @@ -3438,6 +3455,14 @@ class CloneDeserializer : public CloneBase {
m_objectPool.appendWithCrashOnOverflow(value);
}

// Date, RegExp, Error, and the other version 14 terminal types are only counted by
// the serializer's pool from version 14 on, so older payloads must not pool them here.
void addTerminalToObjectPool(JSValue value)
{
if (m_version >= FirstVersionWithPooledTerminals)
addToObjectPool(value);
}

static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length, bool is8Bit)
{
if (length >= std::numeric_limits<int32_t>::max() / sizeof(char16_t))
Expand Down Expand Up @@ -4674,7 +4699,9 @@ class CloneDeserializer : public CloneBase {
}

if (buffer.size() == 0) {
return Bun::JSX509Certificate::create(m_lexicalGlobalObject->vm(), defaultGlobalObject(m_globalObject)->m_JSX509CertificateClassStructure.get(m_globalObject));
auto* cert_obj = Bun::JSX509Certificate::create(m_lexicalGlobalObject->vm(), defaultGlobalObject(m_globalObject)->m_JSX509CertificateClassStructure.get(m_globalObject));
addTerminalToObjectPool(cert_obj);
return cert_obj;
}
ncrypto::ClearErrorOnReturn clear_error_on_return;
X509* ptr = nullptr;
Expand All @@ -4690,6 +4717,7 @@ class CloneDeserializer : public CloneBase {
auto* domGlobalObject = defaultGlobalObject(m_globalObject);
auto* cert_obj = Bun::JSX509Certificate::create(m_lexicalGlobalObject->vm(), domGlobalObject->m_JSX509CertificateClassStructure.get(domGlobalObject), m_globalObject, WTF::move(cert_ptr));
m_gcBuffer.appendWithCrashOnOverflow(cert_obj);
addTerminalToObjectPool(cert_obj);

return cert_obj;
}
Expand All @@ -4715,7 +4743,9 @@ class CloneDeserializer : public CloneBase {

KeyObject keyObject = KeyObject::create(WTF::move(keyData));
Structure* structure = globalObject->m_JSSecretKeyObjectClassStructure.get(m_globalObject);
return JSSecretKeyObject::create(vm, structure, m_globalObject, WTF::move(keyObject));
auto* obj = JSSecretKeyObject::create(vm, structure, m_globalObject, WTF::move(keyObject));
addTerminalToObjectPool(obj);
return obj;
}
case CryptoKeyType::Public:
case CryptoKeyType::Private: {
Expand All @@ -4740,7 +4770,9 @@ class CloneDeserializer : public CloneBase {
}
auto keyObject = KeyObject::create(CryptoKeyType::Public, ncrypto::EVPKeyPointer(pkey));
Structure* structure = globalObject->m_JSPublicKeyObjectClassStructure.get(m_globalObject);
return JSPublicKeyObject::create(vm, structure, m_globalObject, WTF::move(keyObject));
auto* obj = JSPublicKeyObject::create(vm, structure, m_globalObject, WTF::move(keyObject));
addTerminalToObjectPool(obj);
return obj;
}

EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr);
Expand All @@ -4750,7 +4782,9 @@ class CloneDeserializer : public CloneBase {
}
auto keyObject = KeyObject::create(CryptoKeyType::Private, ncrypto::EVPKeyPointer(pkey));
Structure* structure = globalObject->m_JSPrivateKeyObjectClassStructure.get(m_globalObject);
return JSPrivateKeyObject::create(vm, structure, m_globalObject, WTF::move(keyObject));
auto* obj = JSPrivateKeyObject::create(vm, structure, m_globalObject, WTF::move(keyObject));
addTerminalToObjectPool(obj);
return obj;
}
}
}
Expand All @@ -4764,7 +4798,9 @@ class CloneDeserializer : public CloneBase {
if (!readStringData(name))
return JSValue();
auto exception = DOMException::create(message->string(), name->string());
return getJSValue(exception);
JSValue wrapper = getJSValue(exception);
addTerminalToObjectPool(wrapper);
return wrapper;
}

JSValue readBigInt()
Expand Down Expand Up @@ -4868,6 +4904,7 @@ class CloneDeserializer : public CloneBase {
fail();
return JSValue();
}
addTerminalToObjectPool(deserialized);
return deserialized;
}

Expand Down Expand Up @@ -4931,7 +4968,9 @@ class CloneDeserializer : public CloneBase {
double d;
if (!read(d))
return JSValue();
return DateInstance::create(m_lexicalGlobalObject->vm(), m_globalObject->dateStructure(), d);
DateInstance* obj = DateInstance::create(m_lexicalGlobalObject->vm(), m_globalObject->dateStructure(), d);
addTerminalToObjectPool(obj);
return obj;
}
// case FileTag: {
// RefPtr<File> file;
Expand Down Expand Up @@ -5062,7 +5101,9 @@ class CloneDeserializer : public CloneBase {
}
VM& vm = m_lexicalGlobalObject->vm();
RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags.value());
return RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
RegExpObject* obj = RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
addTerminalToObjectPool(obj);
return obj;
}
case ErrorInstanceTag: {
SerializableErrorType serializedErrorType;
Expand Down Expand Up @@ -5095,7 +5136,9 @@ class CloneDeserializer : public CloneBase {
fail();
return JSValue();
}
return ErrorInstance::create(m_lexicalGlobalObject, WTF::move(message), toErrorType(serializedErrorType), { line, column }, WTF::move(sourceURL), WTF::move(stackString));
auto* obj = ErrorInstance::create(m_lexicalGlobalObject, WTF::move(message), toErrorType(serializedErrorType), { line, column }, WTF::move(sourceURL), WTF::move(stackString));
addTerminalToObjectPool(obj);
return obj;
}
case ObjectReferenceTag: {
auto index = readConstantPoolIndex(m_objectPool);
Expand Down Expand Up @@ -5277,6 +5320,7 @@ class CloneDeserializer : public CloneBase {
return JSValue();
}
m_gcBuffer.appendWithCrashOnOverflow(cryptoKey);
addTerminalToObjectPool(cryptoKey);
return cryptoKey;
}
#endif
Expand Down
Loading
Loading