diff options
author | 2023-01-17 23:41:01 -0800 | |
---|---|---|
committer | 2023-01-17 23:41:17 -0800 | |
commit | bd5b90fbf143756f5de8ba5eb560cb6449177300 (patch) | |
tree | 59bcbf7c2cbe91dba887ea1b788410d90ba1e07a | |
parent | bba4054da3a5cbc2f234b9cf4b3ebdb7bb19e69d (diff) | |
download | bun-bd5b90fbf143756f5de8ba5eb560cb6449177300.tar.gz bun-bd5b90fbf143756f5de8ba5eb560cb6449177300.tar.zst bun-bd5b90fbf143756f5de8ba5eb560cb6449177300.zip |
Fix lifetime issue in require.resolve
-rw-r--r-- | src/bun.js/api/bun.zig | 14 | ||||
-rw-r--r-- | src/bun.js/bindings/ImportMetaObject.cpp | 187 | ||||
-rw-r--r-- | src/bun.js/bindings/ImportMetaObject.h | 9 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 13 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.h | 5 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h | 1 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/DOMIsoSubspaces.h | 1 |
7 files changed, 174 insertions, 56 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index bf5b932fc..5b4035256 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -1046,10 +1046,24 @@ export fn Bun__resolveSync( }; } +export fn Bun__resolveSyncWithSource( + global: *JSGlobalObject, + specifier: JSValue, + source: *ZigString, + is_esm: bool, +) JSC.JSValue { + var exception_ = [1]JSC.JSValueRef{null}; + var exception = &exception_; + return doResolveWithArgs(global, specifier.getZigString(global), source.*, exception, is_esm, true) orelse { + return JSC.JSValue.fromRef(exception[0]); + }; +} + comptime { if (!is_bindgen) { _ = Bun__resolve; _ = Bun__resolveSync; + _ = Bun__resolveSyncWithSource; } } diff --git a/src/bun.js/bindings/ImportMetaObject.cpp b/src/bun.js/bindings/ImportMetaObject.cpp index be46e5332..a20ec7abb 100644 --- a/src/bun.js/bindings/ImportMetaObject.cpp +++ b/src/bun.js/bindings/ImportMetaObject.cpp @@ -44,13 +44,13 @@ namespace Zig { using namespace JSC; using namespace WebCore; -static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame, JSC::EncodedJSValue from) +static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame, const WTF::String& fromStr) { JSC::VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); switch (callFrame->argumentCount()) { case 0: { - auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); // not "requires" because "require" could be confusing JSC::throwTypeError(globalObject, scope, "require.resolve needs 1 argument (a string)"_s); scope.release(); @@ -59,8 +59,20 @@ static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject, default: { JSC::JSValue moduleName = callFrame->argument(0); + auto doIt = [&](const WTF::String& fromStr) -> JSC::EncodedJSValue { + ZigString from = Zig::toZigString(fromStr); + auto result = Bun__resolveSyncWithSource(globalObject, JSC::JSValue::encode(moduleName), &from, false); + + if (!JSC::JSValue::decode(result).isString()) { + JSC::throwException(globalObject, scope, JSC::JSValue::decode(result)); + return JSC::JSValue::encode(JSValue {}); + } + + scope.release(); + return result; + }; + if (moduleName.isUndefinedOrNull()) { - auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); JSC::throwTypeError(globalObject, scope, "require.resolve expects a string"_s); scope.release(); return JSC::JSValue::encode(JSC::JSValue {}); @@ -78,59 +90,17 @@ static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject, } } } - } - - auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, false); - auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); - if (!JSC::JSValue::decode(result).isString()) { - JSC::throwException(globalObject, scope, JSC::JSValue::decode(result)); - return JSC::JSValue::encode(JSC::JSValue {}); + if (fromValue.isString()) { + WTF::String str = fromValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {})); + return doIt(str); + } } - scope.release(); - return result; - } + return doIt(fromStr); } -} - -JSC_DEFINE_CUSTOM_SETTER(functionRequireResolveLazySetter, - (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, - JSC::EncodedJSValue value, JSC::PropertyName)) -{ - Zig::GlobalObject* global = static_cast<Zig::GlobalObject*>(JSC::jsCast<JSC::JSObject*>(JSC::JSValue::decode(thisValue))); - JSC::VM& vm = globalObject->vm(); - JSC::JSFunction* require = JSC::jsCast<JSC::JSFunction*>(JSC::JSValue::decode(thisValue)); - auto clientData = WebCore::clientData(vm); - return require->putDirect(vm, PropertyName(clientData->builtinNames().resolvePrivateName()), JSValue::decode(value), 0); -} - -JSC_DEFINE_CUSTOM_GETTER(functionRequireResolveLazyGetter, - (JSC::JSGlobalObject * _globalObject, JSC::EncodedJSValue thisValue, - JSC::PropertyName)) -{ - Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(_globalObject); - - JSC::VM& vm = globalObject->vm(); - auto clientData = WebCore::clientData(vm); - auto& builtinNames = clientData->builtinNames(); - - JSC::JSFunction* require = JSC::jsCast<JSC::JSFunction*>(JSC::JSValue::decode(thisValue)); - - if (JSC::JSValue resolveFunctionValue = require->getIfPropertyExists(globalObject, PropertyName(builtinNames.resolvePrivateName()))) { - return JSValue::encode(resolveFunctionValue); } - - JSValue pathStringValue = require->get(globalObject, PropertyName(builtinNames.pathPrivateName())); - WTF::String pathString = pathStringValue.toWTFString(globalObject); - - JSC::JSFunction* resolverFunction - = JSC::JSNativeStdFunction::create( - globalObject->vm(), globalObject, 2, "resolve"_s, [pathString_ = WTFMove(pathString)](JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) -> const JSC::EncodedJSValue { - return functionRequireResolve(globalObject, callFrame, JSValue::encode(jsString(globalObject->vm(), pathString_))); - }); - require->putDirect(vm, builtinNames.resolvePrivateName(), resolverFunction, 0); - return JSValue::encode(JSValue(resolverFunction)); } Zig::ImportMetaObject* Zig::ImportMetaObject::create(JSC::JSGlobalObject* globalObject, JSValue key) @@ -151,12 +121,121 @@ Zig::ImportMetaObject* Zig::ImportMetaObject::create(JSC::JSGlobalObject* global return create(globalObject, keyString); } -JSObject* Zig::ImportMetaObject::createRequireFunction(VM& vm, JSGlobalObject* globalObject, WTF::String& pathString) +JSC_DECLARE_HOST_FUNCTION(jsFunctionRequireResolve); + +class JSRequireResolveFunctionPrototype final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + + static JSRequireResolveFunctionPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject) + { + auto* structure = createStructure(vm, globalObject, globalObject->functionPrototype()); + JSRequireResolveFunctionPrototype* function = new (NotNull, JSC::allocateCell<JSRequireResolveFunctionPrototype>(vm)) JSRequireResolveFunctionPrototype(vm, structure); + function->finishCreation(vm); + return function; + } + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info()); + } + + DECLARE_INFO; + + static JSC::EncodedJSValue pathsFunction(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) + { + return JSValue::encode(JSC::constructEmptyArray(globalObject, nullptr)); + } + +private: + JSRequireResolveFunctionPrototype(JSC::VM& vm, JSC::Structure* structure) + : JSC::InternalFunction(vm, structure, jsFunctionRequireResolve, jsFunctionRequireResolve) + + { + } + + void finishCreation(JSC::VM& vm) + { + this->putDirectNativeFunction(vm, globalObject(), Identifier::fromString(vm, "paths"_s), 0, pathsFunction, ImplementationVisibility::Public, NoIntrinsic, 0); + Base::finishCreation(vm, 2, "resolve"_s, PropertyAdditionMode::WithoutStructureTransition); + } +}; + +const JSC::ClassInfo JSRequireResolveFunctionPrototype::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRequireResolveFunctionPrototype) }; + +class JSRequireResolveFunction final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + + static JSRequireResolveFunction* create(JSC::VM& vm, JSC::Structure* structure, const WTF::String& from) + { + JSRequireResolveFunction* function = new (NotNull, JSC::allocateCell<JSRequireResolveFunction>(vm)) JSRequireResolveFunction(vm, structure, from); + function->finishCreation(vm); + return function; + } + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info()); + } + + DECLARE_INFO; + + WTF::String from; + + template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + + return WebCore::subspaceForImpl<JSRequireResolveFunction, UseCustomHeapCellType::No>( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForRequireResolveFunction.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForRequireResolveFunction = WTFMove(space); }, + [](auto& spaces) { return spaces.m_subspaceForRequireResolveFunction.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForRequireResolveFunction = WTFMove(space); }); + } + +private: + JSRequireResolveFunction(JSC::VM& vm, JSC::Structure* structure, const WTF::String& from_) + : JSC::InternalFunction(vm, structure, jsFunctionRequireResolve, jsFunctionRequireResolve) + , from(from_) + { + } + + void finishCreation(JSC::VM& vm) + { + Base::finishCreation(vm); + } +}; + +const JSC::ClassInfo JSRequireResolveFunction::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRequireResolveFunction) }; + +JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireResolve, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + JSRequireResolveFunction* thisObject = JSC::jsCast<JSRequireResolveFunction*>(callFrame->jsCallee()); + return functionRequireResolve(globalObject, callFrame, thisObject->from); +} + +JSValue Zig::ImportMetaObject::createResolveFunctionPrototype(JSC::VM& vm, Zig::GlobalObject* globalObject) +{ + return JSRequireResolveFunctionPrototype::create(vm, globalObject); +} + +JSC::Structure* Zig::ImportMetaObject::createResolveFunctionStructure(JSC::VM& vm, Zig::GlobalObject* globalObject) +{ + JSValue prototype = globalObject->requireResolveFunctionPrototype(); + return JSRequireResolveFunction::createStructure(vm, globalObject, prototype); +} + +JSObject* Zig::ImportMetaObject::createRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString) { + Zig::GlobalObject* globalObject = static_cast<Zig::GlobalObject*>(lexicalGlobalObject); JSFunction* requireFunction = JSFunction::create(vm, importMetaObjectRequireCodeGenerator(vm), globalObject); + auto* resolveFunction = JSRequireResolveFunction::create(vm, globalObject->requireResolveFunctionStructure(), pathString); auto clientData = WebCore::clientData(vm); - requireFunction->putDirectCustomAccessor(vm, clientData->builtinNames().resolvePublicName(), JSC::CustomGetterSetter::create(vm, functionRequireResolveLazyGetter, functionRequireResolveLazySetter), 0); - requireFunction->putDirect(vm, clientData->builtinNames().pathPublicName(), jsString(vm, pathString), JSC::PropertyAttribute::DontEnum | 0); + requireFunction->putDirect(vm, clientData->builtinNames().pathPublicName(), jsString(vm, pathString), PropertyAttribute::DontEnum | 0); + requireFunction->putDirect(vm, clientData->builtinNames().resolvePublicName(), resolveFunction, PropertyAttribute::Function | PropertyAttribute::DontDelete | 0); return requireFunction; } diff --git a/src/bun.js/bindings/ImportMetaObject.h b/src/bun.js/bindings/ImportMetaObject.h index ff32c85d4..b9b7cce77 100644 --- a/src/bun.js/bindings/ImportMetaObject.h +++ b/src/bun.js/bindings/ImportMetaObject.h @@ -11,6 +11,7 @@ extern "C" JSC_DECLARE_HOST_FUNCTION(functionImportMeta__resolveSync); extern "C" EncodedJSValue Bun__resolve(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from, bool is_esm); extern "C" EncodedJSValue Bun__resolveSync(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from, bool is_esm); +extern "C" EncodedJSValue Bun__resolveSyncWithSource(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, ZigString* from, bool is_esm); namespace Zig { @@ -28,9 +29,15 @@ public: return ptr; } + static JSC::Structure* createResolveFunctionStructure(JSC::VM& vm, Zig::GlobalObject* globalObject); + static JSValue createResolveFunctionPrototype(JSC::VM& vm, Zig::GlobalObject* globalObject); + static JSObject* createRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString); + static ImportMetaObject* create(JSC::JSGlobalObject* globalObject, JSC::JSValue key); + static inline Zig::ImportMetaObject* create(JSC::JSGlobalObject* globalObject, JSC::JSString* keyString) { + // TODO: optimize this by reusing the same JSC::Structure object and using putDirectOffset auto& vm = globalObject->vm(); auto view = keyString->value(globalObject); JSC::Structure* structure = WebCore::getDOMStructure<Zig::ImportMetaObject>(vm, *reinterpret_cast<Zig::GlobalObject*>(globalObject)); @@ -94,8 +101,6 @@ public: static JSObject* createPrototype(VM& vm, JSDOMGlobalObject& globalObject); static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); - static JSObject* createRequireFunction(VM& vm, JSGlobalObject* globalObject, WTF::String& pathString); - private: ImportMetaObject(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) : Base(vm, structure) diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 10f76c15b..0d88ceac6 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -2582,6 +2582,16 @@ void GlobalObject::finishCreation(VM& vm) init.set(structure); }); + m_requireResolveFunctionStructure.initLater( + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) { + init.set(Zig::ImportMetaObject::createResolveFunctionStructure(init.vm, jsCast<Zig::GlobalObject*>(init.owner))); + }); + + m_resolveFunctionPrototype.initLater( + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) { + init.set(Zig::ImportMetaObject::createResolveFunctionPrototype(init.vm, jsCast<Zig::GlobalObject*>(init.owner)).getObject()); + }); + m_JSFileSinkClassStructure.initLater( [](LazyClassStructure::Initializer& init) { auto* prototype = createJSSinkPrototype(init.vm, init.global, WebCore::SinkID::FileSink); @@ -3463,6 +3473,9 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_emitReadableNextTickFunction.visit(visitor); thisObject->m_JSBufferSubclassStructure.visit(visitor); + thisObject->m_requireResolveFunctionStructure.visit(visitor); + thisObject->m_resolveFunctionPrototype.visit(visitor); + for (auto& barrier : thisObject->m_thenables) { visitor.append(barrier); } diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 36c0356bc..3b8f4c342 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -243,6 +243,9 @@ public: JSC::JSFunction* emitReadableNextTickFunction() { return m_emitReadableNextTickFunction.getInitializedOnMainThread(this); } + Structure* requireResolveFunctionStructure() { return m_requireResolveFunctionStructure.getInitializedOnMainThread(this); } + JSObject* requireResolveFunctionPrototype() { return m_resolveFunctionPrototype.getInitializedOnMainThread(this); } + JSC::JSObject* processObject() { return m_processObject.getInitializedOnMainThread(this); @@ -444,6 +447,8 @@ private: LazyProperty<JSGlobalObject, JSObject> m_subtleCryptoObject; LazyProperty<JSGlobalObject, Structure> m_JSHTTPResponseController; LazyProperty<JSGlobalObject, JSC::Structure> m_JSBufferSubclassStructure; + LazyProperty<JSGlobalObject, JSC::Structure> m_requireResolveFunctionStructure; + LazyProperty<JSGlobalObject, JSObject> m_resolveFunctionPrototype; DOMGuardedObjectSet m_guardedObjects WTF_GUARDED_BY_LOCK(m_gcLock); void* m_bunVM; diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h index aa0eb99a8..5b3605354 100644 --- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h @@ -30,6 +30,7 @@ public: std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForPendingVirtualModuleResult; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForCallSite; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForNapiExternal; + std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForRequireResolveFunction; #include "ZigGeneratedClasses+DOMClientIsoSubspaces.h" /* --- bun --- */ diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h index 3adfa0f44..461a63ac6 100644 --- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h @@ -30,6 +30,7 @@ public: std::unique_ptr<IsoSubspace> m_subspaceForPendingVirtualModuleResult; std::unique_ptr<IsoSubspace> m_subspaceForCallSite; std::unique_ptr<IsoSubspace> m_subspaceForNapiExternal; + std::unique_ptr<IsoSubspace> m_subspaceForRequireResolveFunction; #include "ZigGeneratedClasses+DOMIsoSubspaces.h" /*-- BUN --*/ |