diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 923e76471ce91..79114830bdc46 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -2282,7 +2282,7 @@ declare module "bun" { */ development?: boolean; - error?: (this: Server, request: ErrorLike) => Response | Promise | undefined | Promise; + error?: (this: Server, error: ErrorLike) => Response | Promise | undefined | Promise; /** * Uniquely identify a server instance with an ID diff --git a/src/bun.js/bindings/ErrorCode.cpp b/src/bun.js/bindings/ErrorCode.cpp index 08d06859980f1..f8a1aadd2c690 100644 --- a/src/bun.js/bindings/ErrorCode.cpp +++ b/src/bun.js/bindings/ErrorCode.cpp @@ -7,7 +7,6 @@ #include "JavaScriptCore/ErrorType.h" #include "JavaScriptCore/ObjectConstructor.h" #include "JavaScriptCore/WriteBarrier.h" -#include "root.h" #include "headers-handwritten.h" #include "BunClientData.h" #include "helpers.h" diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp index 8a0aea2c36c00..c88626f780e05 100644 --- a/src/bun.js/bindings/JSBuffer.cpp +++ b/src/bun.js/bindings/JSBuffer.cpp @@ -601,6 +601,11 @@ static inline JSC::EncodedJSValue jsBufferConstructorFunction_allocBody(JSC::JSG } auto startPtr = uint8Array->typedVector() + start; auto str_ = value.toWTFString(lexicalGlobalObject); + if (str_.isEmpty()) { + memset(startPtr, 0, length); + RELEASE_AND_RETURN(scope, JSC::JSValue::encode(uint8Array)); + } + ZigString str = Zig::toZigString(str_); if (UNLIKELY(!Bun__Buffer_fill(&str, startPtr, end - start, encoding))) { diff --git a/src/bun.js/bindings/Weak.cpp b/src/bun.js/bindings/Weak.cpp index 90d4e9839101e..33c885dea4844 100644 --- a/src/bun.js/bindings/Weak.cpp +++ b/src/bun.js/bindings/Weak.cpp @@ -1,7 +1,6 @@ #include "root.h" #include #include "BunClientData.h" -#include "root.h" #include #include diff --git a/src/bun.js/modules/NodeBufferModule.h b/src/bun.js/modules/NodeBufferModule.h index 06546bd04691b..1939384d367ae 100644 --- a/src/bun.js/modules/NodeBufferModule.h +++ b/src/bun.js/modules/NodeBufferModule.h @@ -46,9 +46,8 @@ JSC_DEFINE_HOST_FUNCTION(jsBufferConstructorFunction_isUtf8, } if (UNLIKELY(impl->isDetached())) { - throwTypeError(lexicalGlobalObject, throwScope, - "ArrayBuffer is detached"_s); - return {}; + return Bun::ERR::INVALID_STATE(throwScope, lexicalGlobalObject, + "Cannot validate on a detached buffer"_s); } byteLength = impl->byteLength(); @@ -82,9 +81,8 @@ JSC_DEFINE_HOST_FUNCTION(jsBufferConstructorFunction_isAscii, if (bufferView) { if (UNLIKELY(bufferView->isDetached())) { - throwTypeError(lexicalGlobalObject, throwScope, - "ArrayBufferView is detached"_s); - return {}; + return Bun::ERR::INVALID_STATE(throwScope, lexicalGlobalObject, + "Cannot validate on a detached buffer"_s); } byteLength = bufferView->byteLength(); @@ -169,7 +167,7 @@ DEFINE_NATIVE_MODULE(NodeBuffer) { JSC::jsNumber(MAX_ARRAY_BUFFER_SIZE)); put(JSC::Identifier::fromString(vm, "kStringMaxLength"_s), - JSC::jsNumber(std::numeric_limits().max())); + JSC::jsNumber(WTF::String::MaxLength)); JSC::JSObject *constants = JSC::constructEmptyObject( lexicalGlobalObject, globalObject->objectPrototype(), 2); @@ -177,7 +175,7 @@ DEFINE_NATIVE_MODULE(NodeBuffer) { JSC::jsNumber(MAX_ARRAY_BUFFER_SIZE)); constants->putDirect(vm, JSC::Identifier::fromString(vm, "MAX_STRING_LENGTH"_s), - JSC::jsNumber(std::numeric_limits().max())); + JSC::jsNumber(WTF::String::MaxLength)); put(JSC::Identifier::fromString(vm, "constants"_s), constants); diff --git a/test/js/bun/http/body-leak-test-fixture.ts b/test/js/bun/http/body-leak-test-fixture.ts index f9702c54e1906..1cc5a28298f26 100644 --- a/test/js/bun/http/body-leak-test-fixture.ts +++ b/test/js/bun/http/body-leak-test-fixture.ts @@ -11,7 +11,9 @@ const server = Bun.serve({ }, }); } - if (url.endsWith("/buffering")) { + if (url.endsWith("/json-buffering")) { + await req.json(); + } else if (url.endsWith("/buffering")) { await req.text(); } else if (url.endsWith("/buffering+body-getter")) { req.body; diff --git a/test/js/bun/http/serve-body-leak.test.ts b/test/js/bun/http/serve-body-leak.test.ts index 5c2b7bad65824..273aa918b4c70 100644 --- a/test/js/bun/http/serve-body-leak.test.ts +++ b/test/js/bun/http/serve-body-leak.test.ts @@ -7,6 +7,7 @@ const payload = Buffer.alloc(512 * 1024, "1").toString("utf-8"); // decent size const batchSize = 40; const totalCount = 10_000; const zeroCopyPayload = new Blob([payload]); +const zeroCopyJSONPayload = new Blob([JSON.stringify({ bun: payload })]); let url: URL; let process: Subprocess<"ignore", "pipe", "inherit"> | null = null; @@ -63,6 +64,13 @@ async function callBuffering() { }).then(res => res.text()); expect(result).toBe("Ok"); } +async function callJSONBuffering() { + const result = await fetch(`${url.origin}/json-buffering`, { + method: "POST", + body: zeroCopyJSONPayload, + }).then(res => res.text()); + expect(result).toBe("Ok"); +} async function callBufferingBodyGetter() { const result = await fetch(`${url.origin}/buffering+body-getter`, { @@ -142,6 +150,7 @@ async function calculateMemoryLeak(fn: () => Promise) { for (const test_info of [ ["#10265 should not leak memory when ignoring the body", callIgnore, false, 64], ["should not leak memory when buffering the body", callBuffering, false, 64], + ["should not leak memory when buffering a JSON body", callJSONBuffering, false, 64], ["should not leak memory when buffering the body and accessing req.body", callBufferingBodyGetter, false, 64], ["should not leak memory when streaming the body", callStreaming, false, 64], ["should not leak memory when streaming the body incompletely", callIncompleteStreaming, false, 64], diff --git a/test/js/node/buffer.test.js b/test/js/node/buffer.test.js index 17f25ec067a9b..9eec90f9ed29a 100644 --- a/test/js/node/buffer.test.js +++ b/test/js/node/buffer.test.js @@ -964,6 +964,10 @@ for (let withOverridenBufferWrite of [false, true]) { expect(buf[4]).toBe(128); }); + it("fill(N, empty string) should be the same as fill(N) and not include any uninitialized bytes", () => { + expect(Buffer.alloc(100, "")).toEqual(Buffer.alloc(100)); + }); + // https://github.com/joyent/node/issues/1758 it("check for fractional length args, junk length args, etc.", () => { // Call .fill() first, stops valgrind warning about uninitialized memory reads. @@ -2003,9 +2007,9 @@ for (let withOverridenBufferWrite of [false, true]) { it("constants", () => { expect(BufferModule.constants.MAX_LENGTH).toBe(4294967296); - expect(BufferModule.constants.MAX_STRING_LENGTH).toBe(4294967295); + expect(BufferModule.constants.MAX_STRING_LENGTH).toBe(2147483647); expect(BufferModule.default.constants.MAX_LENGTH).toBe(4294967296); - expect(BufferModule.default.constants.MAX_STRING_LENGTH).toBe(4294967295); + expect(BufferModule.default.constants.MAX_STRING_LENGTH).toBe(2147483647); }); it("File", () => { diff --git a/test/js/node/test/common/index.js b/test/js/node/test/common/index.js index 6494f73197cd3..c67a5b8a81046 100644 --- a/test/js/node/test/common/index.js +++ b/test/js/node/test/common/index.js @@ -409,12 +409,14 @@ if (process.env.NODE_TEST_KNOWN_GLOBALS !== '0') { return leaked; } - process.on('exit', function() { - const leaked = leakedGlobals(); - if (leaked.length > 0) { - assert.fail(`Unexpected global(s) found: ${leaked.join(', ')}`); - } - }); + // --- Commmented out for Bun --- + // process.on('exit', function() { + // const leaked = leakedGlobals(); + // if (leaked.length > 0) { + // assert.fail(`Unexpected global(s) found: ${leaked.join(', ')}`); + // } + // }); + // --- Commmented out for Bun --- } const mustCallChecks = []; @@ -971,7 +973,7 @@ function expectRequiredModule(mod, expectation) { } const common = { - allowGlobals, + allowGlobals: [], buildType, canCreateSymLink, childShouldThrowAndAbort, diff --git a/test/js/node/test/parallel/child-process-exec-timeout-kill.test.js b/test/js/node/test/parallel/child-process-exec-timeout-kill.test.js index 4aa9e93d2608a..e3bc2b8e9b79d 100644 --- a/test/js/node/test/parallel/child-process-exec-timeout-kill.test.js +++ b/test/js/node/test/parallel/child-process-exec-timeout-kill.test.js @@ -34,13 +34,13 @@ test("exec with timeout and killSignal", done => { (err, stdout, stderr) => { console.log("[stdout]", stdout.trim()); console.log("[stderr]", stderr.trim()); - - expect(err.killed).toBe(true); - expect(err.code).toBeNull(); - expect(err.signal).toBe("SIGKILL"); - expect(err.cmd).toBe(cmd); expect(stdout.trim()).toBe(""); expect(stderr.trim()).toBe(""); + + expect(err?.killed).toBe(true); + expect(err?.code).toBeNull(); + expect(err?.signal).toBe("SIGKILL"); + expect(err?.cmd).toBe(cmd); done(); }, );