aboutsummaryrefslogtreecommitdiff
path: root/src/javascript/jsc/api/bun.zig
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-04-29 07:49:48 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-04-29 07:49:48 -0700
commitd49ba5028949f726e68b31093921c2187759ab4b (patch)
tree91fdcf74bc342c872ee7047fe1bd6ca9d3a0fe93 /src/javascript/jsc/api/bun.zig
parent22f74756b4cf173749b2f72fdae438f8def24bd2 (diff)
downloadbun-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.zig102
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,