aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-07-09 22:36:24 -0700
committerGravatar GitHub <noreply@github.com> 2023-07-09 22:36:24 -0700
commit963d4311e614ac197427104b9cf265bbe2a890af (patch)
tree4c912420b7ec13e5c2aabbbb51157a0cac0c98ca
parent2f5e4fffe9554fcc7afa6980b3af6b33bc3a3a5e (diff)
downloadbun-963d4311e614ac197427104b9cf265bbe2a890af.tar.gz
bun-963d4311e614ac197427104b9cf265bbe2a890af.tar.zst
bun-963d4311e614ac197427104b9cf265bbe2a890af.zip
Fixes #3530 (#3587)
* Fixes #3530 * Handle OOM * Add test --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r--src/bun.js/bindings/BunString.cpp23
-rw-r--r--src/bun.js/node/types.zig30
-rw-r--r--src/bun.js/webcore/encoding.zig36
-rw-r--r--src/string.zig26
-rw-r--r--test/js/node/crypto/node-crypto.test.js44
5 files changed, 133 insertions, 26 deletions
diff --git a/src/bun.js/bindings/BunString.cpp b/src/bun.js/bindings/BunString.cpp
index 4c8ff384e..21541d711 100644
--- a/src/bun.js/bindings/BunString.cpp
+++ b/src/bun.js/bindings/BunString.cpp
@@ -169,6 +169,29 @@ extern "C" JSC::EncodedJSValue BunString__toJS(JSC::JSGlobalObject* globalObject
return JSValue::encode(Bun::toJS(globalObject, *bunString));
}
+extern "C" BunString BunString__fromUTF16Unitialized(size_t length)
+{
+ unsigned utf16Length = length;
+ UChar* ptr;
+ auto impl = WTF::StringImpl::createUninitialized(utf16Length, ptr);
+ if (UNLIKELY(!ptr))
+ return { BunStringTag::Dead };
+
+ impl->ref();
+ return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } };
+}
+
+extern "C" BunString BunString__fromLatin1Unitialized(size_t length)
+{
+ unsigned latin1Length = length;
+ LChar* ptr;
+ auto impl = WTF::StringImpl::createUninitialized(latin1Length, ptr);
+ if (UNLIKELY(!ptr))
+ return { BunStringTag::Dead };
+ impl->ref();
+ return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } };
+}
+
extern "C" BunString BunString__fromUTF8(const char* bytes, size_t length)
{
if (simdutf::validate_utf8(bytes, length)) {
diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig
index 553b292d6..642039ba5 100644
--- a/src/bun.js/node/types.zig
+++ b/src/bun.js/node/types.zig
@@ -541,9 +541,18 @@ pub const Encoding = enum(u8) {
const result = JSC.ZigString.init(out).toValueGC(globalThis);
return result;
},
- else => {
- globalThis.throwInvalidArguments("Unexpected encoding", .{});
- return JSC.JSValue.zero;
+ .buffer => {
+ return JSC.ArrayBuffer.createBuffer(globalThis, input);
+ },
+
+ inline else => |enc| {
+ const res = JSC.WebCore.Encoder.toString(input.ptr, size, globalThis, enc);
+ if (res.isError()) {
+ globalThis.throwValue(res);
+ return .zero;
+ }
+
+ return res;
},
}
}
@@ -571,9 +580,18 @@ pub const Encoding = enum(u8) {
const result = JSC.ZigString.init(out).toValueGC(globalThis);
return result;
},
- else => {
- globalThis.throwInvalidArguments("Unexpected encoding", .{});
- return JSC.JSValue.zero;
+ .buffer => {
+ return JSC.ArrayBuffer.createBuffer(globalThis, input);
+ },
+ inline else => |enc| {
+ const res = JSC.WebCore.Encoder.toString(input.ptr, input.len, globalThis, enc);
+
+ if (res.isError()) {
+ globalThis.throwValue(res);
+ return .zero;
+ }
+
+ return res;
},
}
}
diff --git a/src/bun.js/webcore/encoding.zig b/src/bun.js/webcore/encoding.zig
index bb1180acb..dd47ccc29 100644
--- a/src/bun.js/webcore/encoding.zig
+++ b/src/bun.js/webcore/encoding.zig
@@ -829,23 +829,18 @@ pub const Encoder = struct {
return ZigString.init(input).toValueGC(global);
}
- if (input.len < 512) {
- var buf: [512]u8 = undefined;
- var to = buf[0..input.len];
- strings.copyLatin1IntoASCII(to, input);
- return ZigString.init(to).toValueGC(global);
- }
-
- var to = allocator.alloc(u8, len) catch return ZigString.init("Out of memory").toErrorInstance(global);
- strings.copyLatin1IntoASCII(to, input);
- return ZigString.init(to).toExternalValue(global);
+ var str = bun.String.createUninitialized(.latin1, len) orelse return ZigString.init("Out of memory").toErrorInstance(global);
+ defer str.deref();
+ strings.copyLatin1IntoASCII(@constCast(str.latin1()), input);
+ return str.toJS(global);
},
.latin1 => {
- var to = allocator.alloc(u8, len) catch return ZigString.init("Out of memory").toErrorInstance(global);
+ var str = bun.String.createUninitialized(.latin1, len) orelse return ZigString.init("Out of memory").toErrorInstance(global);
+ defer str.deref();
- @memcpy(to, input_ptr[0..to.len]);
+ @memcpy(@constCast(str.latin1()), input_ptr[0..len]);
- return ZigString.init(to).toExternalValue(global);
+ return str.toJS(global);
},
.buffer, .utf8 => {
const converted = strings.toUTF16Alloc(allocator, input, false) catch return ZigString.init("Out of memory").toErrorInstance(global);
@@ -861,21 +856,22 @@ pub const Encoder = struct {
// Avoid incomplete characters
if (len / 2 == 0) return ZigString.Empty.toValue(global);
- var output = allocator.alloc(u16, len / 2) catch return ZigString.init("Out of memory").toErrorInstance(global);
- var output_bytes = std.mem.sliceAsBytes(output);
+ var output = bun.String.createUninitialized(.utf16, len / 2) orelse return ZigString.init("Out of memory").toErrorInstance(global);
+ defer output.deref();
+ var output_bytes = std.mem.sliceAsBytes(@constCast(output.utf16()));
output_bytes[output_bytes.len - 1] = 0;
@memcpy(output_bytes, input_ptr[0..output_bytes.len]);
- return ZigString.toExternalU16(output.ptr, output.len, global);
+ return output.toJS(global);
},
.hex => {
- var output = allocator.alloc(u8, input.len * 2) catch return ZigString.init("Out of memory").toErrorInstance(global);
+ var str = bun.String.createUninitialized(.latin1, len * 2) orelse return ZigString.init("Out of memory").toErrorInstance(global);
+ defer str.deref();
+ var output = @constCast(str.latin1());
const wrote = strings.encodeBytesToHex(output, input);
std.debug.assert(wrote == output.len);
- var val = ZigString.init(output);
- val.mark();
- return val.toExternalValue(global);
+ return str.toJS(global);
},
.base64url => {
diff --git a/src/string.zig b/src/string.zig
index 166a0a6f7..5f107197f 100644
--- a/src/string.zig
+++ b/src/string.zig
@@ -257,6 +257,8 @@ pub const String = extern struct {
extern fn BunString__fromLatin1(bytes: [*]const u8, len: usize) String;
extern fn BunString__fromBytes(bytes: [*]const u8, len: usize) String;
+ extern fn BunString__fromLatin1Unitialized(len: usize) String;
+ extern fn BunString__fromUTF16Unitialized(len: usize) String;
pub fn toOwnedSlice(this: String, allocator: std.mem.Allocator) ![]u8 {
switch (this.tag) {
@@ -278,6 +280,30 @@ pub const String = extern struct {
}
}
+ pub fn createUninitializedLatin1(len: usize) String {
+ JSC.markBinding(@src());
+ return BunString__fromLatin1Unitialized(len);
+ }
+
+ pub fn createUninitializedUTF16(len: usize) String {
+ JSC.markBinding(@src());
+ return BunString__fromUTF16Unitialized(len);
+ }
+
+ pub fn createUninitialized(comptime kind: @Type(.EnumLiteral), len: usize) ?String {
+ const without_check = switch (comptime kind) {
+ .latin1 => createUninitializedLatin1(len),
+ .utf16 => createUninitializedUTF16(len),
+ else => @compileError("Invalid string kind"),
+ };
+
+ if (without_check.tag == .Dead) {
+ return null;
+ }
+
+ return without_check;
+ }
+
pub fn createLatin1(bytes: []const u8) String {
JSC.markBinding(@src());
return BunString__fromLatin1(bytes.ptr, bytes.len);
diff --git a/test/js/node/crypto/node-crypto.test.js b/test/js/node/crypto/node-crypto.test.js
index 5a68540cf..2489f96c7 100644
--- a/test/js/node/crypto/node-crypto.test.js
+++ b/test/js/node/crypto/node-crypto.test.js
@@ -43,6 +43,50 @@ describe("createHash", () => {
expect(Buffer.isBuffer(hash.digest())).toBeTrue();
});
+ const otherEncodings = {
+ ucs2: [
+ 11626, 2466, 37699, 38942, 64564, 53010, 48101, 47943, 44761, 18499, 12442, 26994, 46434, 62582, 39395, 20542,
+ ],
+ latin1: [
+ 106, 45, 162, 9, 67, 147, 30, 152, 52, 252, 18, 207, 229, 187, 71, 187, 217, 174, 67, 72, 154, 48, 114, 105, 98,
+ 181, 118, 244, 227, 153, 62, 80,
+ ],
+ binary: [
+ 106, 45, 162, 9, 67, 147, 30, 152, 52, 252, 18, 207, 229, 187, 71, 187, 217, 174, 67, 72, 154, 48, 114, 105, 98,
+ 181, 118, 244, 227, 153, 62, 80,
+ ],
+ base64: [
+ 97, 105, 50, 105, 67, 85, 79, 84, 72, 112, 103, 48, 47, 66, 76, 80, 53, 98, 116, 72, 117, 57, 109, 117, 81, 48,
+ 105, 97, 77, 72, 74, 112, 89, 114, 86, 50, 57, 79, 79, 90, 80, 108, 65, 61,
+ ],
+ hex: [
+ 54, 97, 50, 100, 97, 50, 48, 57, 52, 51, 57, 51, 49, 101, 57, 56, 51, 52, 102, 99, 49, 50, 99, 102, 101, 53, 98,
+ 98, 52, 55, 98, 98, 100, 57, 97, 101, 52, 51, 52, 56, 57, 97, 51, 48, 55, 50, 54, 57, 54, 50, 98, 53, 55, 54, 102,
+ 52, 101, 51, 57, 57, 51, 101, 53, 48,
+ ],
+ ascii: [
+ 106, 45, 34, 9, 67, 19, 30, 24, 52, 124, 18, 79, 101, 59, 71, 59, 89, 46, 67, 72, 26, 48, 114, 105, 98, 53, 118,
+ 116, 99, 25, 62, 80,
+ ],
+ utf8: [
+ 106, 45, 65533, 9, 67, 65533, 30, 65533, 52, 65533, 18, 65533, 65533, 71, 65533, 1646, 67, 72, 65533, 48, 114,
+ 105, 98, 65533, 118, 65533, 65533, 62, 80,
+ ],
+ };
+
+ for (let encoding in otherEncodings) {
+ it("digest " + encoding, () => {
+ const hash = crypto.createHash("sha256");
+ hash.update("some data to hash");
+ expect(
+ hash
+ .digest(encoding)
+ .split("")
+ .map(a => a.charCodeAt(0)),
+ ).toEqual(otherEncodings[encoding]);
+ });
+ }
+
it("stream (sync)", () => {
const hash = crypto.createHash("sha256");
hash.write("some data to hash");