diff options
author | 2022-04-29 07:49:48 -0700 | |
---|---|---|
committer | 2022-04-29 07:49:48 -0700 | |
commit | d49ba5028949f726e68b31093921c2187759ab4b (patch) | |
tree | 91fdcf74bc342c872ee7047fe1bd6ca9d3a0fe93 /src/javascript/jsc/api/bun.zig | |
parent | 22f74756b4cf173749b2f72fdae438f8def24bd2 (diff) | |
download | bun-d49ba5028949f726e68b31093921c2187759ab4b.tar.gz bun-d49ba5028949f726e68b31093921c2187759ab4b.tar.zst bun-d49ba5028949f726e68b31093921c2187759ab4b.zip |
[bun.js] Implement unsafe.{`arrayBufferToPtr`, `arrayBufferFromPtr`, `bufferFromPtr`}
Diffstat (limited to 'src/javascript/jsc/api/bun.zig')
-rw-r--r-- | src/javascript/jsc/api/bun.zig | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/javascript/jsc/api/bun.zig b/src/javascript/jsc/api/bun.zig index ff6e63724..34e9b7645 100644 --- a/src/javascript/jsc/api/bun.zig +++ b/src/javascript/jsc/api/bun.zig @@ -1862,10 +1862,112 @@ pub const Unsafe = struct { .arrayBufferToString = .{ .rfn = arrayBufferToString, }, + .arrayBufferToPtr = .{ + .rfn = JSC.wrapWithHasContainer(Unsafe, "arrayBufferToPtr", false, false), + }, + .arrayBufferFromPtr = .{ + .rfn = JSC.wrapWithHasContainer(Unsafe, "arrayBufferFromPtr", false, false), + }, + .bufferFromPtr = .{ + .rfn = JSC.wrapWithHasContainer(Unsafe, "bufferFromPtr", false, false), + }, }, .{}, ); + const ValueOrError = union(enum) { + err: JSValue, + slice: []u8, + }; + + pub fn arrayBufferToPtr(globalThis: *JSGlobalObject, value: JSValue) JSValue { + if (value.isEmpty()) { + return JSC.JSValue.jsNull(); + } + + const array_buffer = value.asArrayBuffer(globalThis) orelse { + return JSC.toInvalidArguments("Expected ArrayBufferView", .{}, globalThis.ref()); + }; + + if (array_buffer.len == 0) { + return JSC.toInvalidArguments("ArrayBufferView must have a length > 0. A pointer to empty memory doesn't work", .{}, globalThis.ref()); + } + + return JSC.JSValue.jsNumber(@bitCast(f64, @ptrToInt(array_buffer.ptr))); + } + + fn getPtrSlice(globalThis: *JSGlobalObject, value: JSValue, valueLength: JSValue) ValueOrError { + if (!value.isNumber()) { + return .{ .err = JSC.toInvalidArguments("ptr must be a number.", .{}, globalThis.ref()) }; + } + + const num = value.asNumber(); + if (num == 0) { + return .{ .err = JSC.toInvalidArguments("ptr cannot be zero, that would segfault Bun :(", .{}, globalThis.ref()) }; + } + + if (!std.math.isFinite(num)) { + return .{ .err = JSC.toInvalidArguments("ptr must be a finite number.", .{}, globalThis.ref()) }; + } + + const addr = @bitCast(usize, num); + + if (addr == 0xDEADBEEF or addr == 0xaaaaaaaa or addr == 0xAAAAAAAA) { + return .{ .err = JSC.toInvalidArguments("ptr to invalid memory, that would segfault Bun :(", .{}, globalThis.ref()) }; + } + + if (!valueLength.isNumber()) { + return .{ .err = JSC.toInvalidArguments("length must be a number.", .{}, globalThis.ref()) }; + } + + if (valueLength.asNumber() == 0.0) { + return .{ .err = JSC.toInvalidArguments("length must be > 0. This usually means a bug in your code.", .{}, globalThis.ref()) }; + } + + const length_i = valueLength.toInt64(); + if (length_i < 0) { + return .{ .err = JSC.toInvalidArguments("length must be > 0. This usually means a bug in your code.", .{}, globalThis.ref()) }; + } + + if (length_i > std.math.maxInt(u48)) { + return .{ .err = JSC.toInvalidArguments("length exceeds max addressable memory. This usually means a bug in your code.", .{}, globalThis.ref()) }; + } + + const length = @intCast(usize, length_i); + + return .{ .slice = @intToPtr([*]u8, addr)[0..length] }; + } + + pub fn arrayBufferFromPtr( + globalThis: *JSGlobalObject, + value: JSValue, + valueLength: JSValue, + ) JSC.JSValue { + switch (getPtrSlice(globalThis, value, valueLength)) { + .err => |erro| { + return erro; + }, + .slice => |slice| { + return JSC.ArrayBuffer.fromBytes(slice, JSC.JSValue.JSType.ArrayBuffer).toJSWithContext(globalThis.ref(), null, null, null); + }, + } + } + + pub fn bufferFromPtr( + globalThis: *JSGlobalObject, + value: JSValue, + valueLength: JSValue, + ) JSC.JSValue { + switch (getPtrSlice(globalThis, value, valueLength)) { + .err => |erro| { + return erro; + }, + .slice => |slice| { + return JSC.JSValue.createBuffer(globalThis, slice, null); + }, + } + } + // For testing the segfault handler pub fn __debug__doSegfault( _: void, |