aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-06-10 02:26:48 -0700
committerGravatar GitHub <noreply@github.com> 2023-06-10 02:26:48 -0700
commita2ec2ea397e96dd7bb64177964e11bf4c9a4b91b (patch)
tree33338c794afc142a7b137b6cfea7da6dea37fccb
parentf51878a8ec64f313c63e790543477c934184954c (diff)
downloadbun-a2ec2ea397e96dd7bb64177964e11bf4c9a4b91b.tar.gz
bun-a2ec2ea397e96dd7bb64177964e11bf4c9a4b91b.tar.zst
bun-a2ec2ea397e96dd7bb64177964e11bf4c9a4b91b.zip
Fixes #3250 (#3269)
* Fixes #3250 We must call `EVP_MD_CTX_cleanup` because `EVP_MD_CTX` containers pointers inside to allocated memory * Fix leak * Update sha.zig --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r--src/bun.js/api/bun.zig36
-rw-r--r--src/bun.js/base.zig23
-rw-r--r--src/sha.zig5
3 files changed, 51 insertions, 13 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index 7e9e3ca30..72815d9a2 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -1533,7 +1533,6 @@ pub const Crypto = struct {
var ctx: BoringSSL.EVP_MD_CTX = undefined;
BoringSSL.EVP_MD_CTX_init(&ctx);
_ = BoringSSL.EVP_DigestInit_ex(&ctx, md, engine);
-
return .{
.ctx = ctx,
.md = md,
@@ -1615,6 +1614,11 @@ pub const Crypto = struct {
defer name_str.deinit();
return byNameAndEngine(global.bunVM().rareData().boringEngine(), name_str.slice());
}
+
+ pub fn deinit(this: *EVP) void {
+ // https://github.com/oven-sh/bun/issues/3250
+ _ = BoringSSL.EVP_MD_CTX_cleanup(&this.ctx);
+ }
};
fn createCryptoError(globalThis: *JSC.JSGlobalObject, err_code: u32) JSValue {
@@ -1867,6 +1871,7 @@ pub const Crypto = struct {
// we use SHA512 to hash the password if it's longer than 72 bytes
if (password.len > 72) {
var sha_256 = bun.sha.SHA512.init();
+ defer sha_256.deinit();
sha_256.update(password);
sha_256.final(outbuf[0..bun.sha.SHA512.digest]);
password_to_use = outbuf[0..bun.sha.SHA512.digest];
@@ -2469,10 +2474,11 @@ pub const Crypto = struct {
fn hashToEncoding(
globalThis: *JSGlobalObject,
evp: *EVP,
- input: JSC.Node.StringOrBuffer,
+ input: JSC.Node.SliceOrBuffer,
encoding: JSC.Node.Encoding,
) JSC.JSValue {
var output_digest_buf: Digest = undefined;
+ defer input.deinit();
const len = evp.hash(globalThis.bunVM().rareData().boringEngine(), input.slice(), &output_digest_buf) orelse {
const err = BoringSSL.ERR_get_error();
@@ -2487,11 +2493,12 @@ pub const Crypto = struct {
fn hashToBytes(
globalThis: *JSGlobalObject,
evp: *EVP,
- input: JSC.Node.StringOrBuffer,
+ input: JSC.Node.SliceOrBuffer,
output: ?JSC.ArrayBuffer,
) JSC.JSValue {
var output_digest_buf: Digest = undefined;
var output_digest_slice: []u8 = &output_digest_buf;
+ defer input.deinit();
if (output) |output_buf| {
const size = evp.size();
var bytes = output_buf.byteSlice();
@@ -2513,21 +2520,22 @@ pub const Crypto = struct {
if (output) |output_buf| {
return output_buf.value;
} else {
- var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, output_digest_slice[0..len]) catch unreachable, .Uint8Array);
- return array_buffer_out.toJSUnchecked(globalThis, null);
+ // Clone to GC-managed memory
+ return JSC.ArrayBuffer.create(globalThis, output_digest_slice[0..len], .Buffer);
}
}
pub fn hash_(
globalThis: *JSGlobalObject,
algorithm: ZigString,
- input: JSC.Node.StringOrBuffer,
+ input: JSC.Node.SliceOrBuffer,
output: ?JSC.Node.StringOrBuffer,
) JSC.JSValue {
var evp = EVP.byName(algorithm, globalThis) orelse {
globalThis.throwInvalidArguments("Unsupported algorithm \"{any}\"", .{algorithm});
return .zero;
};
+ defer evp.deinit();
if (output) |string_or_buffer| {
switch (string_or_buffer) {
@@ -2624,13 +2632,14 @@ pub const Crypto = struct {
pub fn digest_(
this: *@This(),
globalThis: *JSGlobalObject,
- output: ?JSC.Node.StringOrBuffer,
+ output: ?JSC.Node.SliceOrBuffer,
) JSC.JSValue {
if (output) |string_or_buffer| {
switch (string_or_buffer) {
.string => |str| {
- const encoding = JSC.Node.Encoding.from(str) orelse {
- globalThis.throwInvalidArguments("Unknown encoding: {s}", .{str});
+ defer str.deinit();
+ const encoding = JSC.Node.Encoding.from(str.slice()) orelse {
+ globalThis.throwInvalidArguments("Unknown encoding: {}", .{str});
return JSC.JSValue.zero;
};
@@ -2667,8 +2676,8 @@ pub const Crypto = struct {
if (output) |output_buf| {
return output_buf.value;
} else {
- var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, result) catch unreachable, .Uint8Array);
- return array_buffer_out.toJSUnchecked(globalThis, null);
+ // Clone to GC-managed memory
+ return JSC.ArrayBuffer.create(globalThis, result, .Buffer);
}
}
@@ -2683,7 +2692,10 @@ pub const Crypto = struct {
}
pub fn finalize(this: *CryptoHasher) callconv(.C) void {
- VirtualMachine.get().allocator.destroy(this);
+ // https://github.com/oven-sh/bun/issues/3250
+ this.evp.deinit();
+
+ bun.default_allocator.destroy(this);
}
};
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig
index 9b9cacbe7..cd0684398 100644
--- a/src/bun.js/base.zig
+++ b/src/bun.js/base.zig
@@ -3125,6 +3125,29 @@ pub fn wrapStaticMethod(
args[i] = null;
}
},
+ JSC.Node.SliceOrBuffer => {
+ const arg = iter.nextEat() orelse {
+ globalThis.throwInvalidArguments("expected string or buffer", .{});
+ iter.deinit();
+ return JSC.JSValue.zero;
+ };
+ args[i] = JSC.Node.SliceOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg) orelse {
+ globalThis.throwInvalidArguments("expected string or buffer", .{});
+ iter.deinit();
+ return JSC.JSValue.zero;
+ };
+ },
+ ?JSC.Node.SliceOrBuffer => {
+ if (iter.nextEat()) |arg| {
+ args[i] = JSC.Node.SliceOrBuffer.fromJS(globalThis.ptr(), iter.arena.allocator(), arg) orelse {
+ globalThis.throwInvalidArguments("expected string or buffer", .{});
+ iter.deinit();
+ return JSC.JSValue.zero;
+ };
+ } else {
+ args[i] = null;
+ }
+ },
JSC.ArrayBuffer => {
if (iter.nextEat()) |arg| {
args[i] = arg.asArrayBuffer(globalThis.ptr()) orelse {
diff --git a/src/sha.zig b/src/sha.zig
index 64539eff0..cd9fd0f0a 100644
--- a/src/sha.zig
+++ b/src/sha.zig
@@ -74,6 +74,10 @@ fn NewEVP(
pub fn final(this: *@This(), out: *Digest) void {
std.debug.assert(BoringSSL.EVP_DigestFinal(&this.ctx, out, null) == 1);
}
+
+ pub fn deinit(this: *@This()) void {
+ _ = BoringSSL.EVP_MD_CTX_cleanup(&this.ctx);
+ }
};
}
pub const EVP = struct {
@@ -331,4 +335,3 @@ pub fn main() anyerror!void {
// std.crypto.hash.sha2.Sha256.hash(value, &hash2, .{});
// try std.testing.expectEqual(hash, hash2);
// }
-