Throw ERR_INVALID_THIS in DOM types (#13484)

This commit is contained in:
Jarred Sumner
2024-08-22 23:25:41 -07:00
committed by GitHub
parent 94ee538dc6
commit ac8db43485
9 changed files with 63 additions and 20 deletions

View File

@@ -35,8 +35,11 @@
#include <wtf/RefCounted.h>
#include <wtf/text/WTFString.h>
#include "blob.h"
namespace WebCore {
class ScriptExecutionContext;
template<typename> class ExceptionOr;
class HTMLElement;
class HTMLFormElement;
@@ -84,6 +87,7 @@ public:
size_t m_index { 0 };
};
Iterator createIterator() { return Iterator { *this }; }
Iterator createIterator(const ScriptExecutionContext* context) { return Iterator { *this }; }
private:
// explicit DOMFormData(ScriptExecutionContext*, const PAL::TextEncoding& = PAL::UTF8Encoding());

View File

@@ -399,6 +399,11 @@ extern "C" JSC::EncodedJSValue WebCore__CommonAbortReason__toJS(JSC::JSGlobalObj
return JSC::JSValue::encode(WebCore::toJS(globalObject, abortReason));
}
JSC::JSObject* Bun::createInvalidThisError(JSC::JSGlobalObject* globalObject, const String& message)
{
return Bun::createError(globalObject, Bun::ErrorCode::ERR_INVALID_THIS, message);
}
JSC::JSObject* Bun::createInvalidThisError(JSC::JSGlobalObject* globalObject, JSC::JSValue thisValue, const ASCIILiteral typeName)
{
if (thisValue.isEmpty() || thisValue.isUndefined()) {
@@ -408,4 +413,9 @@ JSC::JSObject* Bun::createInvalidThisError(JSC::JSGlobalObject* globalObject, JS
// Pathological case: the this value returns a string which is extremely long or causes an out of memory error.
const auto& typeString = thisValue.isString() ? String("a string"_s) : JSC::errorDescriptionForValue(globalObject, thisValue);
return Bun::createError(globalObject, Bun::ErrorCode::ERR_INVALID_THIS, makeString("Expected this to be instanceof "_s, typeName, ", but received "_s, typeString));
}
JSC::EncodedJSValue Bun::throwError(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope, Bun::ErrorCode code, const WTF::String& message)
{
return JSC::JSValue::encode(scope.throwException(globalObject, createError(globalObject, code, message)));
}

View File

@@ -46,12 +46,14 @@ private:
void finishCreation(VM&);
};
JSC::EncodedJSValue throwError(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope, ErrorCode code, const WTF::String& message);
JSC::JSObject* createError(Zig::GlobalObject* globalObject, ErrorCode code, const WTF::String& message);
JSC::JSObject* createError(JSC::JSGlobalObject* globalObject, ErrorCode code, const WTF::String& message);
JSC::JSObject* createError(Zig::GlobalObject* globalObject, ErrorCode code, JSC::JSValue message);
JSC::JSObject* createError(VM& vm, Zig::GlobalObject* globalObject, ErrorCode code, JSValue message, JSValue options = jsUndefined());
JSC::JSValue toJS(JSC::JSGlobalObject*, ErrorCode);
JSObject* createInvalidThisError(JSGlobalObject* globalObject, JSValue thisValue, const ASCIILiteral typeName);
JSObject* createInvalidThisError(JSGlobalObject* globalObject, const String& message);
JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_INVALID_ARG_TYPE);
JSC_DECLARE_HOST_FUNCTION(jsFunction_ERR_OUT_OF_RANGE);

View File

@@ -71,6 +71,8 @@ enum ExceptionCode {
// Used to indicate to the bindings that a JS exception was thrown below and it should be propagated.
ExistingExceptionError,
InvalidThisError,
};
} // namespace WebCore
@@ -116,7 +118,8 @@ template<> struct EnumTraits<WebCore::ExceptionCode> {
WebCore::ExceptionCode::TypeError,
WebCore::ExceptionCode::JSSyntaxError,
WebCore::ExceptionCode::StackOverflowError,
WebCore::ExceptionCode::ExistingExceptionError>;
WebCore::ExceptionCode::ExistingExceptionError,
WebCore::ExceptionCode::InvalidThisError>;
};
} // namespace WTF

View File

@@ -21,6 +21,8 @@
#include "root.h"
#include "ErrorCode.h"
#include "DOMException.h"
#include "JSDOMException.h"
#include "JSDOMExceptionHandling.h"
@@ -173,6 +175,9 @@ JSValue createDOMException(JSGlobalObject* lexicalGlobalObject, ExceptionCode ec
case ExceptionCode::OutOfMemoryError:
return createOutOfMemoryError(lexicalGlobalObject);
case ExceptionCode::InvalidThisError:
return Bun::createInvalidThisError(lexicalGlobalObject, message.isEmpty() ? "Expected this to be of a different type"_s : message);
default: {
// FIXME: All callers to createDOMException need to pass in the correct global object.
// For now, we're going to assume the lexicalGlobalObject. Which is wrong in cases like this:
@@ -233,22 +238,22 @@ void throwSecurityError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScop
JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, ASCIILiteral argumentName, ASCIILiteral functionInterfaceName, ASCIILiteral functionName, ASCIILiteral expectedValues)
{
return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, functionInterfaceName, functionName, "one of: "_s, expectedValues));
return Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, makeArgumentTypeErrorMessage(argumentIndex, argumentName, functionInterfaceName, functionName, "one of: "_s, expectedValues));
}
JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, ASCIILiteral argumentName, ASCIILiteral interfaceName, ASCIILiteral functionName)
{
return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, interfaceName, functionName, "a function"_s));
return Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, makeArgumentTypeErrorMessage(argumentIndex, argumentName, interfaceName, functionName, "a function"_s));
}
JSC::EncodedJSValue throwArgumentMustBeObjectError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, ASCIILiteral argumentName, ASCIILiteral interfaceName, ASCIILiteral functionName)
{
return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, interfaceName, functionName, "an object"_s));
return Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, makeArgumentTypeErrorMessage(argumentIndex, argumentName, interfaceName, functionName, "an object"_s));
}
JSC::EncodedJSValue throwArgumentTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, unsigned argumentIndex, ASCIILiteral argumentName, ASCIILiteral functionInterfaceName, ASCIILiteral functionName, ASCIILiteral expectedType)
{
return throwVMTypeError(&lexicalGlobalObject, scope, makeArgumentTypeErrorMessage(argumentIndex, argumentName, functionInterfaceName, functionName, "an instance of "_s, expectedType));
return Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, makeArgumentTypeErrorMessage(argumentIndex, argumentName, functionInterfaceName, functionName, "an instance of "_s, expectedType));
}
void throwAttributeTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral interfaceName, ASCIILiteral attributeName, ASCIILiteral expectedType)
@@ -258,7 +263,7 @@ void throwAttributeTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::Thro
JSC::EncodedJSValue throwRequiredMemberTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral memberName, ASCIILiteral dictionaryName, ASCIILiteral expectedType)
{
return throwVMTypeError(&lexicalGlobalObject, scope, makeString("Member "_s, dictionaryName, '.', memberName, " is required and must be an instance of "_s, expectedType));
return Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, makeString("Member "_s, dictionaryName, '.', memberName, " is required and must be an instance of "_s, expectedType));
}
JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, ASCIILiteral interfaceName)
@@ -268,7 +273,7 @@ JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::
void throwSequenceTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope)
{
throwTypeError(lexicalGlobalObject, scope, "Value is not a sequence"_s);
Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "Value is not a sequence"_s);
}
void throwNonFiniteTypeError(JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope)
@@ -294,12 +299,12 @@ String makeUnsupportedIndexedSetterErrorMessage(ASCIILiteral interfaceName)
EncodedJSValue throwThisTypeError(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, const char* interfaceName, const char* functionName)
{
return throwTypeError(lexicalGlobalObject, scope, makeThisTypeErrorMessage(interfaceName, functionName));
return JSValue::encode(scope.throwException(&lexicalGlobalObject, Bun::createInvalidThisError(&lexicalGlobalObject, makeThisTypeErrorMessage(interfaceName, functionName))));
}
JSC::EncodedJSValue rejectPromiseWithThisTypeError(DeferredPromise& promise, const char* interfaceName, const char* methodName)
{
promise.reject(ExceptionCode::TypeError, makeThisTypeErrorMessage(interfaceName, methodName));
promise.reject(ExceptionCode::InvalidThisError, makeThisTypeErrorMessage(interfaceName, methodName));
return JSValue::encode(jsUndefined());
}

View File

@@ -34,6 +34,7 @@
namespace WebCore {
class DOMURL;
class ScriptExecutionContext;
class URLSearchParams : public RefCounted<URLSearchParams> {
public:
@@ -66,6 +67,7 @@ public:
size_t m_index { 0 };
};
Iterator createIterator() { return Iterator { *this }; }
Iterator createIterator(const ScriptExecutionContext* context) { return Iterator { *this }; }
private:
const Vector<KeyValuePair<String, String>>& pairs() const { return m_pairs; }

View File

@@ -35,7 +35,11 @@
#include <wtf/Vector.h>
namespace WebCore {
class ScriptExecutionContext;
DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(FetchHeaders);
class FetchHeaders : public RefCounted<FetchHeaders> {
WTF_MAKE_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(FetchHeaders);
@@ -103,6 +107,11 @@ public:
return Iterator(*this, lowerCaseKeys);
}
Iterator createIterator(const ScriptExecutionContext* context)
{
return Iterator(*this, true);
}
void setInternalHeaders(HTTPHeaderMap&& headers) { m_headers = WTFMove(headers); }
const HTTPHeaderMap& internalHeaders() const { return m_headers; }

View File

@@ -30,7 +30,8 @@
#include <JavaScriptCore/IteratorPrototype.h>
#include <JavaScriptCore/PropertySlot.h>
#include <type_traits>
#include "ErrorCode.h"
#include "JavaScriptCore/Interpreter.h"
namespace WebCore {
void addValueIterableMethods(JSC::JSGlobalObject&, JSC::JSObject&);
@@ -101,7 +102,9 @@ public:
static Prototype* createPrototype(JSC::VM& vm, JSC::JSGlobalObject& globalObject)
{
return Prototype::create(vm, &globalObject, Prototype::createStructure(vm, &globalObject, globalObject.iteratorPrototype()));
auto* structure = Prototype::createStructure(vm, &globalObject, globalObject.iteratorPrototype());
structure->setMayBePrototype(true);
return Prototype::create(vm, &globalObject, structure);
}
JSC::JSValue next(JSC::JSGlobalObject&);
@@ -111,7 +114,7 @@ public:
protected:
JSDOMIteratorBase(JSC::Structure* structure, JSWrapper& iteratedObject, IterationKind kind)
: Base(structure, *iteratedObject.globalObject())
, m_iterator(iteratedObject.wrapped().createIterator())
, m_iterator(iteratedObject.wrapped().createIterator(iteratedObject.globalObject()->scriptExecutionContext()))
, m_kind(kind)
{
}
@@ -211,10 +214,12 @@ template<typename JSIterator> JSC::JSValue iteratorForEach(JSC::JSGlobalObject&
JSC::JSValue thisValue = callFrame.argument(1);
auto callData = JSC::getCallData(callback);
if (callData.type == JSC::CallData::Type::None)
return throwTypeError(&lexicalGlobalObject, scope, "Cannot call callback"_s);
if (callData.type == JSC::CallData::Type::None) {
Bun::throwError(&lexicalGlobalObject, scope, Bun::ErrorCode::ERR_INVALID_ARG_TYPE, "Cannot call callback on a non-function"_s);
return {};
}
auto iterator = thisObject.wrapped().createIterator();
auto iterator = thisObject.wrapped().createIterator(JSC::jsCast<JSDOMGlobalObject*>(&lexicalGlobalObject)->scriptExecutionContext());
while (auto value = iterator.next()) {
JSC::MarkedArgumentBuffer arguments;
appendForEachArguments<JSIterator>(lexicalGlobalObject, *thisObject.globalObject(), arguments, value);
@@ -256,8 +261,9 @@ JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSDOMIteratorPrototype<JSWrapper, I
auto scope = DECLARE_THROW_SCOPE(vm);
auto iterator = JSC::jsDynamicCast<JSDOMIteratorBase<JSWrapper, IteratorTraits>*>(callFrame->thisValue());
if (!iterator)
return JSC::JSValue::encode(throwTypeError(globalObject, scope, "Cannot call next() on a non-Iterator object"_s));
if (!iterator) {
return Bun::throwError(globalObject, scope, Bun::ErrorCode::ERR_INVALID_THIS, "Cannot call next() on a non-Iterator object"_s);
}
return JSC::JSValue::encode(iterator->next(*globalObject));
}
@@ -268,8 +274,8 @@ void JSDOMIteratorPrototype<JSWrapper, IteratorTraits>::finishCreation(JSC::VM&
Base::finishCreation(vm);
ASSERT(inherits(info()));
JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->next, next, 0, 0, ImplementationVisibility::Public, JSC::NoIntrinsic);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->next, next, 0, 0, JSC::ImplementationVisibility::Public);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}
}
}

View File

@@ -38,6 +38,8 @@
#include <JavaScriptCore/JSONObject.h>
#include <JavaScriptCore/JSPromiseConstructor.h>
#include <JavaScriptCore/Strong.h>
#include "ErrorCode.h"
#include "JavaScriptCore/ErrorInstance.h"
namespace WebCore {
using namespace JSC;
@@ -241,7 +243,7 @@ JSC::EncodedJSValue createRejectedPromiseWithTypeError(JSC::JSGlobalObject& lexi
auto promiseConstructor = globalObject.promiseConstructor();
auto rejectFunction = promiseConstructor->get(&lexicalGlobalObject, vm.propertyNames->builtinNames().rejectPrivateName());
RETURN_IF_EXCEPTION(scope, {});
auto* rejectionValue = static_cast<ErrorInstance*>(createTypeError(&lexicalGlobalObject, errorMessage));
ErrorInstance* rejectionValue = static_cast<ErrorInstance*>(cause == RejectedPromiseWithTypeErrorCause::InvalidThis ? Bun::createInvalidThisError(&lexicalGlobalObject, errorMessage) : createTypeError(&lexicalGlobalObject, errorMessage));
if (cause == RejectedPromiseWithTypeErrorCause::NativeGetter)
rejectionValue->setNativeGetterTypeError();