diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index f3e549726d..39bd6ca07d 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -279,6 +279,21 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen, } WTF::String filename = callFrame->uncheckedArgument(1).toWTFString(globalObject); + if (filename.isEmpty()) { + JSC::throwTypeError(globalObject, scope, "dlopen requires a non-empty string as the second argument"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + if (filename.startsWith("file://"_s)) { + WTF::URL fileURL = WTF::URL(filename); + if (!fileURL.isValid() || !fileURL.protocolIsFile()) { + JSC::throwTypeError(globalObject, scope, "invalid file: URL passed to dlopen"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + filename = fileURL.fileSystemPath(); + } + // Support embedded .node files // See StandaloneModuleGraph.zig for what this "$bunfs" thing is #if OS(WINDOWS) diff --git a/test/js/node/process/process.test.js b/test/js/node/process/process.test.js index 162c39697e..faa1a9fea8 100644 --- a/test/js/node/process/process.test.js +++ b/test/js/node/process/process.test.js @@ -533,6 +533,20 @@ it("dlopen args parsing", () => { expect(() => process.dlopen({ module: { exports: Symbol("123") } }, Symbol("badddd"))).toThrow(); }); +it("dlopen accepts file: URLs", () => { + const mod = { exports: {} }; + try { + process.dlopen(mod, import.meta.url); + throw "Expected error"; + } catch (e) { + expect(e.message).not.toContain("file:"); + } + + expect(() => process.dlopen(mod, "file://asd[kasd[po@[p1o23]1po!-10923-095-@$@8123=-9123=-0==][pc;!")).toThrow( + "invalid file: URL passed to dlopen", + ); +}); + it("process.constrainedMemory()", () => { if (process.platform === "linux") { // On Linux, it returns 0 if the kernel doesn't support it