aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-08-19 18:17:16 -0700
committerGravatar GitHub <noreply@github.com> 2023-08-19 18:17:16 -0700
commit507761b4637a83d10e2f8b64ff870881bba7c14b (patch)
treecb3a2920ed18832df3c7075bd8e21b15b1184a3d
parent196620183fd20ca42b363c5f947af1dc979f888f (diff)
downloadbun-507761b4637a83d10e2f8b64ff870881bba7c14b.tar.gz
bun-507761b4637a83d10e2f8b64ff870881bba7c14b.tar.zst
bun-507761b4637a83d10e2f8b64ff870881bba7c14b.zip
Fix crash impacting sharp & resvg (#4221)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r--src/bun.js/base.zig38
-rw-r--r--src/bun.js/bindings/JSBuffer.cpp2
-rw-r--r--src/bun.js/bindings/napi.cpp49
-rw-r--r--src/napi/napi.zig26
-rw-r--r--test/js/third_party/resvg/bbox.test.js31
5 files changed, 73 insertions, 73 deletions
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig
index dbb208284..b08b82c40 100644
--- a/src/bun.js/base.zig
+++ b/src/bun.js/base.zig
@@ -771,44 +771,6 @@ comptime {
std.testing.refAllDecls(RefString);
}
-// TODO: remove this abstraction and make it work directly with
-pub const ExternalBuffer = struct {
- global: *JSC.JSGlobalObject,
- ctx: ?*anyopaque = null,
- function: JSC.napi.napi_finalize = null,
- allocator: std.mem.Allocator,
- buf: []u8 = &[_]u8{},
-
- pub fn create(ctx: ?*anyopaque, buf: []u8, global: *JSC.JSGlobalObject, function: JSC.napi.napi_finalize, allocator: std.mem.Allocator) !*ExternalBuffer {
- var container = try allocator.create(ExternalBuffer);
- container.* = .{
- .ctx = ctx,
- .global = global,
- .allocator = allocator,
- .function = function,
- .buf = buf,
- };
- return container;
- }
-
- pub fn toJS(this: *ExternalBuffer, ctx: *JSC.JSGlobalObject) JSC.JSValue {
- return JSC.JSValue.createBufferWithCtx(ctx, this.buf, this, ExternalBuffer_deallocator);
- }
-
- pub fn toArrayBuffer(this: *ExternalBuffer, ctx: *JSC.JSGlobalObject) JSC.JSValue {
- return JSValue.c(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy(ctx.ref(), this.buf.ptr, this.buf.len, ExternalBuffer_deallocator, this, null));
- }
-};
-pub export fn ExternalBuffer_deallocator(bytes_: *anyopaque, ctx: *anyopaque) callconv(.C) void {
- var external: *ExternalBuffer = bun.cast(*ExternalBuffer, ctx);
- if (external.function) |function| {
- function(external.global, external.ctx, bytes_);
- }
-
- const allocator = external.allocator;
- allocator.destroy(external);
-}
-
pub export fn MarkedArrayBuffer_deallocator(bytes_: *anyopaque, _: *anyopaque) void {
const mimalloc = @import("../allocators/mimalloc.zig");
// zig's memory allocator interface won't work here
diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp
index 16c0e64b6..934fc9b6c 100644
--- a/src/bun.js/bindings/JSBuffer.cpp
+++ b/src/bun.js/bindings/JSBuffer.cpp
@@ -202,7 +202,7 @@ JSC::EncodedJSValue JSBuffer__bufferFromPointerAndLengthAndDeinit(JSC::JSGlobalO
auto* subclassStructure = globalObject->JSBufferSubclassStructure();
if (LIKELY(length > 0)) {
- auto buffer = ArrayBuffer::createFromBytes(ptr, length, createSharedTask<void(void*)>([=](void* p) {
+ auto buffer = ArrayBuffer::createFromBytes(ptr, length, createSharedTask<void(void*)>([ctx, bytesDeallocator](void* p) {
if (bytesDeallocator)
bytesDeallocator(p, ctx);
}));
diff --git a/src/bun.js/bindings/napi.cpp b/src/bun.js/bindings/napi.cpp
index 237f3d554..393c133e1 100644
--- a/src/bun.js/bindings/napi.cpp
+++ b/src/bun.js/bindings/napi.cpp
@@ -1551,6 +1551,55 @@ extern "C" napi_status napi_get_property_names(napi_env env, napi_value object,
return napi_ok;
}
+extern "C" napi_status napi_create_external_buffer(napi_env env, size_t length,
+ void* data,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_value* result)
+{
+ if (UNLIKELY(result == nullptr)) {
+ return napi_invalid_arg;
+ }
+
+ Zig::GlobalObject* globalObject = toJS(env);
+ JSC::VM& vm = globalObject->vm();
+
+ auto arrayBuffer = ArrayBuffer::createFromBytes(data, length, createSharedTask<void(void*)>([globalObject, finalize_hint, finalize_cb](void* p) {
+ if (finalize_cb != nullptr) {
+ finalize_cb(toNapi(globalObject), p, finalize_hint);
+ }
+ }));
+ auto* subclassStructure = globalObject->JSBufferSubclassStructure();
+
+ auto* buffer = JSC::JSUint8Array::create(globalObject, subclassStructure, WTFMove(arrayBuffer), 0, length);
+
+ *result = toNapi(buffer);
+ return napi_ok;
+}
+
+extern "C" napi_status napi_create_external_arraybuffer(napi_env env, void* external_data, size_t byte_length,
+ napi_finalize finalize_cb, void* finalize_hint, napi_value* result)
+{
+ if (UNLIKELY(result == nullptr)) {
+ return napi_invalid_arg;
+ }
+
+ Zig::GlobalObject* globalObject = toJS(env);
+ JSC::VM& vm = globalObject->vm();
+
+ auto arrayBuffer = ArrayBuffer::createFromBytes(external_data, byte_length, createSharedTask<void(void*)>([globalObject, finalize_hint, finalize_cb](void* p) {
+ if (finalize_cb != nullptr) {
+ finalize_cb(toNapi(globalObject), p, finalize_hint);
+ }
+ }));
+
+ auto* buffer = JSC::JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(ArrayBufferSharingMode::Shared), WTFMove(arrayBuffer));
+
+ *result = toNapi(buffer);
+
+ return napi_ok;
+}
+
extern "C" napi_status napi_get_value_string_utf8(napi_env env,
napi_value napiValue, char* buf,
size_t bufsize,
diff --git a/src/napi/napi.zig b/src/napi/napi.zig
index 9d361a14e..ac428028b 100644
--- a/src/napi/napi.zig
+++ b/src/napi/napi.zig
@@ -707,20 +707,8 @@ pub export fn napi_create_arraybuffer(env: napi_env, byte_length: usize, data: [
return .ok;
}
-pub export fn napi_create_external_arraybuffer(env: napi_env, external_data: ?*anyopaque, byte_length: usize, finalize_cb: napi_finalize, finalize_hint: ?*anyopaque, result: *napi_value) napi_status {
- log("napi_create_external_arraybuffer", .{});
- var external = JSC.ExternalBuffer.create(
- finalize_hint,
- @as([*]u8, @ptrCast(external_data.?))[0..byte_length],
- env,
- finalize_cb,
- env.bunVM().allocator,
- ) catch {
- return genericFailure();
- };
- result.* = external.toArrayBuffer(env);
- return .ok;
-}
+pub extern fn napi_create_external_arraybuffer(env: napi_env, external_data: ?*anyopaque, byte_length: usize, finalize_cb: napi_finalize, finalize_hint: ?*anyopaque, result: *napi_value) napi_status;
+
pub export fn napi_get_arraybuffer_info(env: napi_env, arraybuffer: napi_value, data: ?*[*]u8, byte_length: ?*usize) napi_status {
log("napi_get_arraybuffer_info", .{});
const array_buffer = arraybuffer.asArrayBuffer(env) orelse return .arraybuffer_expected;
@@ -1072,15 +1060,7 @@ pub export fn napi_create_buffer(env: napi_env, length: usize, data: ?**anyopaqu
result.* = buffer;
return .ok;
}
-pub export fn napi_create_external_buffer(env: napi_env, length: usize, data: ?*anyopaque, finalize_cb: napi_finalize, finalize_hint: ?*anyopaque, result: *napi_value) napi_status {
- log("napi_create_external_buffer: {d}", .{length});
- var buf = JSC.ExternalBuffer.create(finalize_hint, @as([*]u8, @ptrCast(data.?))[0..length], env, finalize_cb, bun.default_allocator) catch {
- return genericFailure();
- };
-
- result.* = buf.toJS(env);
- return .ok;
-}
+pub extern fn napi_create_external_buffer(env: napi_env, length: usize, data: ?*anyopaque, finalize_cb: napi_finalize, finalize_hint: ?*anyopaque, result: *napi_value) napi_status;
pub export fn napi_create_buffer_copy(env: napi_env, length: usize, data: [*]u8, result_data: ?*?*anyopaque, result: *napi_value) napi_status {
log("napi_create_buffer_copy: {d}", .{length});
var buffer = JSC.JSValue.createBufferFromLength(env, length);
diff --git a/test/js/third_party/resvg/bbox.test.js b/test/js/third_party/resvg/bbox.test.js
index d80e99cdd..0c8a19578 100644
--- a/test/js/third_party/resvg/bbox.test.js
+++ b/test/js/third_party/resvg/bbox.test.js
@@ -1,6 +1,16 @@
import { test, expect } from "bun:test";
import { Resvg } from "@resvg/resvg-js";
+const opts = {
+ fitTo: {
+ mode: "width",
+ value: 500,
+ },
+ font: {
+ loadSystemFonts: false,
+ },
+};
+
const svg = `<svg viewBox="-40 0 180 260" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g fill="green" transform="rotate(-10 50 100) translate(-36 45.5) skewX(40) scale(1 0.5)">
<path id="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" />
@@ -20,16 +30,6 @@ for (let Class of [
},
]) {
test(`bbox ${Class.name}`, () => {
- const opts = {
- fitTo: {
- mode: "width",
- value: 500,
- },
- font: {
- loadSystemFonts: false,
- },
- };
-
const resvg = new Class(svg, opts);
const bbox = resvg.getBBox();
@@ -37,11 +37,12 @@ for (let Class of [
expect(resvg.height).toBe(260);
if (bbox) resvg.cropByBBox(bbox);
- const pngData = resvg.render();
expect(bbox.width).toBe(112.20712208389321);
expect(bbox.height).toBe(81);
+ const pngData = resvg.render();
+
expect(pngData.width).toBe(500);
expect(pngData.height).toBe(362);
@@ -51,3 +52,11 @@ for (let Class of [
}
});
}
+
+test("napi_create_external_buffer", () => {
+ const resvg = new Resvg(svg, opts);
+ for (let i = 0; i < 10; i++) {
+ resvg.render().asPng();
+ Bun.gc();
+ }
+});