diff options
author | 2023-08-19 18:17:16 -0700 | |
---|---|---|
committer | 2023-08-19 18:17:16 -0700 | |
commit | 507761b4637a83d10e2f8b64ff870881bba7c14b (patch) | |
tree | cb3a2920ed18832df3c7075bd8e21b15b1184a3d | |
parent | 196620183fd20ca42b363c5f947af1dc979f888f (diff) | |
download | bun-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.zig | 38 | ||||
-rw-r--r-- | src/bun.js/bindings/JSBuffer.cpp | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/napi.cpp | 49 | ||||
-rw-r--r-- | src/napi/napi.zig | 26 | ||||
-rw-r--r-- | test/js/third_party/resvg/bbox.test.js | 31 |
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(); + } +}); |