diff --git a/src/jsc/array_buffer.rs b/src/jsc/array_buffer.rs index c6ecad51243..c2e8180ff2d 100644 --- a/src/jsc/array_buffer.rs +++ b/src/jsc/array_buffer.rs @@ -923,15 +923,13 @@ impl MarkedArrayBuffer { } pub fn from_string(str: &[u8]) -> Result { - // allocator.dupe(u8, str) → Box::<[u8]>::from(str), but we need a raw - // pointer because the buffer is later freed via the default allocator - // (`MarkedArrayBuffer_deallocator` → `default_alloc::free`). - let buf: Box<[u8]> = Box::from(str); - let len = buf.len(); - let ptr = bun_core::heap::into_raw(buf).cast::(); - // SAFETY: ptr/len from heap::alloc; backed by the global allocator. - let bytes = unsafe { bun_core::ffi::slice_mut(ptr, len) }; - Ok(MarkedArrayBuffer::from_bytes(bytes, JSType::Uint8Array)) + // allocator.dupe(u8, str) → Box::<[u8]>::from(str); the buffer is later + // freed via the default allocator (`MarkedArrayBuffer_deallocator` → + // `default_alloc::free`). + Ok(MarkedArrayBuffer::from_owned_bytes( + Box::from(str), + JSType::Uint8Array, + )) } pub fn from_js(global: &JSGlobalObject, value: JSValue) -> Option { @@ -952,9 +950,14 @@ impl MarkedArrayBuffer { }) } - pub fn from_bytes(bytes: &mut [u8], typed_array_type: JSType) -> MarkedArrayBuffer { + /// Take ownership of a default-allocator `Box<[u8]>` and wrap it as an + /// owning `MarkedArrayBuffer`. The buffer is freed exactly once: either by + /// [`MarkedArrayBuffer::destroy`] or by the deallocator installed when the + /// buffer is handed to JSC (`to_js` / `to_node_buffer` — the handoff + /// clears `owns_buffer`, so a later `destroy()` is a no-op). + pub fn from_owned_bytes(bytes: Box<[u8]>, typed_array_type: JSType) -> MarkedArrayBuffer { MarkedArrayBuffer { - buffer: ArrayBuffer::from_bytes(bytes, typed_array_type), + buffer: ArrayBuffer::from_owned_bytes(bytes, typed_array_type), owns_buffer: true, pinned: false, } @@ -977,17 +980,27 @@ impl MarkedArrayBuffer { } /// Releases the owned byte buffer if this `MarkedArrayBuffer` was created with an - /// allocator (e.g. via `from_string`/`from_bytes`). Does not free the struct itself; + /// allocator (e.g. via `from_string`/`from_owned_bytes`). Does not free the struct itself; /// `MarkedArrayBuffer` is passed and stored by value, so callers own its storage. pub fn destroy(&mut self) { if self.owns_buffer { self.owns_buffer = false; - // SAFETY: buffer.ptr was allocated by the global allocator (heap::alloc / allocator.dupe). - unsafe { bun_alloc::default_alloc::free(self.buffer.ptr.cast()) }; + // An empty `Box<[u8]>` has no backing allocation — `from_owned_bytes` + // stored its dangling pointer, so there is nothing to free (same + // reasoning as `JSValue::create_buffer_from_box`). + if self.buffer.byte_len != 0 { + // SAFETY: `owns_buffer` is only set by `from_owned_bytes`, which + // took the pointer from a non-empty default-allocator `Box<[u8]>`. + unsafe { bun_alloc::default_alloc::free(self.buffer.ptr.cast()) }; + } } } - pub fn to_node_buffer(&self, global: &JSGlobalObject) -> JSValue { + pub fn to_node_buffer(&mut self, global: &JSGlobalObject) -> JSValue { + // `create_buffer` installs `MarkedArrayBuffer_deallocator` over + // non-empty bytes, making JSC the owner; clear `owns_buffer` so a + // later `destroy()` cannot free the allocation a second time. + self.owns_buffer = false; // `JSValue::create_buffer` takes `&mut [u8]` (ownership transfers to JSC // via the deallocator). `ArrayBuffer` is `Copy` over a raw pointer, so // copy the descriptor and project a mutable slice. @@ -995,10 +1008,16 @@ impl MarkedArrayBuffer { JSValue::create_buffer(global, buf.byte_slice_mut()) } - pub fn to_js(&self, global: &JSGlobalObject) -> JsResult { + pub fn to_js(&mut self, global: &JSGlobalObject) -> JsResult { if !self.buffer.value.is_empty_or_undefined_or_null() { return Ok(self.buffer.value); } + // Both paths below hand the bytes to JSC (the non-empty one installs + // `MarkedArrayBuffer_deallocator`, making JSC the owner). Clear + // `owns_buffer` before the fallible FFI call so a later `destroy()` + // cannot double-free: if the call throws, the bytes may leak, which + // is the safe direction. + self.owns_buffer = false; if self.buffer.byte_len == 0 { return make_typed_array_with_bytes_no_copy( global, diff --git a/src/runtime/api/bun/Terminal.rs b/src/runtime/api/bun/Terminal.rs index 18bc8315148..d6fb9f49452 100644 --- a/src/runtime/api/bun/Terminal.rs +++ b/src/runtime/api/bun/Terminal.rs @@ -1796,11 +1796,11 @@ impl Terminal { return true; } v.extend_from_slice(chunk); - // MarkedArrayBuffer::from_bytes takes a `&mut [u8]` it will own (freed - // via mimalloc on the C++ side) — leak the Box and hand over the slice. - let bytes: &'static mut [u8] = Box::leak(v.into_boxed_slice()); - let data = MarkedArrayBuffer::from_bytes(bytes, jsc::JSType::Uint8Array) - .to_node_buffer(global_this); + // Ownership of the boxed slice transfers to JSC (freed via the + // deallocator installed by `to_node_buffer`). + let data = + MarkedArrayBuffer::from_owned_bytes(v.into_boxed_slice(), jsc::JSType::Uint8Array) + .to_node_buffer(global_this); global_this.bun_vm().event_loop_mut().run_callback( callback, diff --git a/src/runtime/api/bun/subprocess/Readable.rs b/src/runtime/api/bun/subprocess/Readable.rs index 54eb8e21293..9271c3accb7 100644 --- a/src/runtime/api/bun/subprocess/Readable.rs +++ b/src/runtime/api/bun/subprocess/Readable.rs @@ -310,12 +310,10 @@ impl Readable { // Ownership of the mimalloc-backed buffer transfers to JSC // (freed via `MarkedArrayBuffer_deallocator`). - Ok(jsc::MarkedArrayBuffer { - buffer: jsc::ArrayBuffer::from_owned_bytes(own, jsc::JSType::Uint8Array), - owns_buffer: true, - pinned: false, - } - .to_node_buffer(global)) + Ok( + jsc::MarkedArrayBuffer::from_owned_bytes(own, jsc::JSType::Uint8Array) + .to_node_buffer(global), + ) } _ => Ok(JSValue::UNDEFINED), } diff --git a/src/runtime/api/bun/subprocess/SubprocessPipeReader.rs b/src/runtime/api/bun/subprocess/SubprocessPipeReader.rs index 91a58ac4dad..4f34b4130b0 100644 --- a/src/runtime/api/bun/subprocess/SubprocessPipeReader.rs +++ b/src/runtime/api/bun/subprocess/SubprocessPipeReader.rs @@ -308,14 +308,14 @@ impl PipeReader { match &mut self.state { State::Done(bytes) => { let bytes = core::mem::take(bytes); - // `state.done` is now empty via `take()`. - // `MarkedArrayBuffer::from_bytes` takes a borrowed `&mut [u8]` - // with `owns_buffer = true` (freed via mimalloc on the JS side); leak the - // boxed slice so JS becomes the owner — same pattern as - // `MarkedArrayBuffer::from_string`. - let slice: &'static mut [u8] = Box::leak(bytes.into_boxed_slice()); - MarkedArrayBuffer::from_bytes(slice, jsc::JSType::Uint8Array) - .to_node_buffer(global_this) + // `state.done` is now empty via `take()`. Ownership of the + // boxed slice transfers to JSC (freed via the deallocator + // installed by `to_node_buffer`). + MarkedArrayBuffer::from_owned_bytes( + bytes.into_boxed_slice(), + jsc::JSType::Uint8Array, + ) + .to_node_buffer(global_this) } _ => JSValue::UNDEFINED, } diff --git a/src/runtime/node/node_fs.rs b/src/runtime/node/node_fs.rs index 09caf024833..1e476051bfc 100644 --- a/src/runtime/node/node_fs.rs +++ b/src/runtime/node/node_fs.rs @@ -4716,14 +4716,14 @@ pub mod ret { // items dropped here (auto free) Ok(array) } - Readdir::Buffers(items) => { + Readdir::Buffers(mut items) => { // `JSValue.fromAny(_, []Buffer, _)` — generic-slice arm: // build an empty array, push `item.toJS(globalObject)` for // each. Ownership of every `Buffer`'s bytes transfers to // JSC via `MarkedArrayBuffer::to_js`; the boxed slice // itself is freed when `items` drops. let array = JSValue::create_empty_array(global_object, items.len())?; - for (i, item) in items.iter().enumerate() { + for (i, item) in items.iter_mut().enumerate() { let res = item.to_js(global_object)?; if res == JSValue::ZERO { return Ok(JSValue::ZERO); @@ -7069,16 +7069,10 @@ impl NodeFS { if let Some(file) = unsafe { &mut *graph }.find(path.as_bytes()) { let contents: &[u8] = file.contents.as_bytes(); return if args.encoding == Encoding::Buffer { - // PORTING.md §Forbidden bans `Vec::leak()`; round-trip through - // `into_boxed_slice()` so the allocation layout JSC frees with - // matches what we hand it (capacity == len). - let raw = - bun_core::heap::into_raw(contents.to_vec().into_boxed_slice()); - // SAFETY: ownership of the allocation is transferred to JSC; the - // ArrayBuffer finalizer reconstructs the Box and frees it - // (PORTING.md:348 — `heap::alloc`/`from_raw` across FFI). - Ok(ret::ReadFileWithOptions::Buffer(Buffer::from_bytes( - unsafe { &mut *raw }, + // Ownership of the boxed slice transfers to JSC; the + // ArrayBuffer finalizer frees it. + Ok(ret::ReadFileWithOptions::Buffer(Buffer::from_owned_bytes( + contents.to_vec().into_boxed_slice(), bun_jsc::JSType::Uint8Array, ))) } else if string_type == ReadFileStringType::Default { @@ -7209,15 +7203,12 @@ impl NodeFS { }; } } - let raw = bun_core::heap::into_raw( + // Ownership of the boxed slice transfers to JSC; the + // ArrayBuffer finalizer frees it. + Ok(ret::ReadFileWithOptions::Buffer(Buffer::from_owned_bytes( temporary_read_buffer_before_stat_call .to_vec() .into_boxed_slice(), - ); - // SAFETY: ownership transferred to JSC; freed via ArrayBuffer finalizer - // (PORTING.md:348 — `heap::alloc`/`from_raw` across FFI). - Ok(ret::ReadFileWithOptions::Buffer(Buffer::from_bytes( - unsafe { &mut *raw }, bun_jsc::JSType::Uint8Array, ))) } @@ -7377,11 +7368,10 @@ impl NodeFS { match args.encoding { Encoding::Buffer => { buf.truncate(final_len); - let raw = bun_core::heap::into_raw(buf.into_boxed_slice()); - // SAFETY: ownership transferred to JSC; freed via ArrayBuffer finalizer - // (PORTING.md:348 — `heap::alloc`/`from_raw` across FFI). - Ok(ret::ReadFileWithOptions::Buffer(Buffer::from_bytes( - unsafe { &mut *raw }, + // Ownership of the boxed slice transfers to JSC; the + // ArrayBuffer finalizer frees it. + Ok(ret::ReadFileWithOptions::Buffer(Buffer::from_owned_bytes( + buf.into_boxed_slice(), bun_jsc::JSType::Uint8Array, ))) } diff --git a/src/runtime/shell/subproc.rs b/src/runtime/shell/subproc.rs index 7051305d3e7..39ad849e60f 100644 --- a/src/runtime/shell/subproc.rs +++ b/src/runtime/shell/subproc.rs @@ -2305,12 +2305,9 @@ impl PipeReader { pub fn to_buffer(&mut self, global_this: &JSGlobalObject) -> JSValue { match &mut self.state { PipeReaderState::Done(bytes) => { - // `MarkedArrayBuffer::from_bytes` adopts the allocation (freed - // by the JSC ArrayBuffer destructor). `heap::release` names that - // FFI hand-off — it is `Box::leak` under the hood; the JSC - // ArrayBuffer destructor is the reclaim, not this scope. - let slice: &'static mut [u8] = bun_core::heap::release(core::mem::take(bytes)); - MarkedArrayBuffer::from_bytes(slice, jsc::JSType::Uint8Array) + // Ownership of the boxed slice transfers to JSC (freed via the + // deallocator installed by `to_node_buffer`). + MarkedArrayBuffer::from_owned_bytes(core::mem::take(bytes), jsc::JSType::Uint8Array) .to_node_buffer(global_this) } _ => JSValue::UNDEFINED, diff --git a/test/regression/marked-array-buffer-ownership-soundness-fixture/.gitignore b/test/regression/marked-array-buffer-ownership-soundness-fixture/.gitignore new file mode 100644 index 00000000000..ea8c4bf7f35 --- /dev/null +++ b/test/regression/marked-array-buffer-ownership-soundness-fixture/.gitignore @@ -0,0 +1 @@ +/target diff --git a/test/regression/marked-array-buffer-ownership-soundness-fixture/Cargo.lock b/test/regression/marked-array-buffer-ownership-soundness-fixture/Cargo.lock new file mode 100644 index 00000000000..19a53914bf5 --- /dev/null +++ b/test/regression/marked-array-buffer-ownership-soundness-fixture/Cargo.lock @@ -0,0 +1,2389 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bun_alloc" +version = "0.0.0" +dependencies = [ + "allocator-api2", + "bitflags", + "bstr", + "bumpalo", + "bun_mimalloc_sys", + "bun_opaque", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "typed-arena", +] + +[[package]] +name = "bun_analytics" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "bun_semver", + "bun_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_api" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_collections", + "bun_install_types", + "bun_options_types", + "bun_url", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_ast" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bumpalo", + "bun_alloc", + "bun_collections", + "bun_core", + "bun_dispatch", + "bun_paths", + "bun_perf", + "bun_ptr", + "bun_sys", + "bun_wyhash", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "typed-arena", +] + +[[package]] +name = "bun_base64" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bumpalo", + "bun_alloc", + "bun_collections", + "bun_core", + "bun_simdutf_sys", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_boringssl" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_boringssl_sys", + "bun_cares_sys", + "bun_core", + "bun_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_boringssl_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "bun_opaque", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_brotli" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_brotli_sys", + "bun_core", + "bun_io", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_brotli_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_opaque", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_bundler" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bumpalo", + "bun_alloc", + "bun_analytics", + "bun_ast", + "bun_base64", + "bun_collections", + "bun_core", + "bun_crash_handler", + "bun_css", + "bun_dispatch", + "bun_dotenv", + "bun_event_loop", + "bun_glob", + "bun_hash", + "bun_http_types", + "bun_io", + "bun_js_parser", + "bun_js_printer", + "bun_lolhtml_sys", + "bun_md", + "bun_opaque", + "bun_options_types", + "bun_parsers", + "bun_paths", + "bun_perf", + "bun_ptr", + "bun_resolve_builtins", + "bun_resolver", + "bun_router", + "bun_sourcemap", + "bun_sys", + "bun_threading", + "bun_url", + "bun_watcher", + "bun_wyhash", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", + "typed-arena", +] + +[[package]] +name = "bun_bunfig" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_analytics", + "bun_api", + "bun_ast", + "bun_bundler", + "bun_clap", + "bun_collections", + "bun_core", + "bun_install_types", + "bun_io", + "bun_js_parser", + "bun_options_types", + "bun_parsers", + "bun_paths", + "bun_resolver", + "bun_standalone_graph", + "bun_sys", + "bun_url", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_cares_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_core", + "bun_libuv_sys", + "bun_opaque", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_clap" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_clap_macros", + "bun_core", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_clap_macros" +version = "0.0.0" +dependencies = [ + "bun_output_tags", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bun_collections" +version = "0.0.0" +dependencies = [ + "allocator-api2", + "bun_alloc", + "bun_core", + "bun_ptr", + "bun_simdutf_sys", + "bun_wyhash", + "hashbrown 0.15.5", + "paste", + "rustc-hash", + "smallvec", + "strum", + "thiserror", +] + +[[package]] +name = "bun_core" +version = "0.0.0" +dependencies = [ + "bstr", + "bun_alloc", + "bun_core_macros", + "bun_dispatch", + "bun_hash", + "bun_highway", + "bun_opaque", + "bun_output_tags", + "bun_simdutf_sys", + "bun_windows_sys", + "bun_wyhash", + "bytemuck", + "const_format", + "itoa", + "libc", + "strum", + "thiserror", +] + +[[package]] +name = "bun_core_macros" +version = "0.0.0" +dependencies = [ + "bun_output_tags", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bun_crash_handler" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_analytics", + "bun_ast", + "bun_base64", + "bun_collections", + "bun_core", + "bun_dispatch", + "bun_io", + "bun_options_types", + "bun_paths", + "bun_ptr", + "bun_sys", + "bun_threading", + "bun_which", + "bun_zlib", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_css" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bumpalo", + "bun_alloc", + "bun_ast", + "bun_base64", + "bun_collections", + "bun_core", + "bun_css_derive", + "bun_io", + "bun_paths", + "bun_ptr", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "typed-arena", +] + +[[package]] +name = "bun_css_derive" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bun_dispatch" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bun_dns" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_cares_sys", + "bun_core", + "bun_sys", + "bun_windows_sys", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_dotenv" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_ast", + "bun_collections", + "bun_core", + "bun_dispatch", + "bun_paths", + "bun_sys", + "bun_url", + "bun_which", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_errno" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "bun_libuv_sys", + "bun_windows_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_event_loop" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_collections", + "bun_core", + "bun_dispatch", + "bun_dotenv", + "bun_io", + "bun_paths", + "bun_ptr", + "bun_sys", + "bun_threading", + "bun_uws", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_exe_format" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_core", + "bun_sha_hmac", + "bun_sys", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_glob" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_collections", + "bun_core", + "bun_paths", + "bun_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_hash" +version = "0.0.0" +dependencies = [ + "bun_highway", +] + +[[package]] +name = "bun_highway" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_http" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_analytics", + "bun_ast", + "bun_base64", + "bun_boringssl", + "bun_boringssl_sys", + "bun_brotli", + "bun_collections", + "bun_core", + "bun_dispatch", + "bun_dns", + "bun_dotenv", + "bun_event_loop", + "bun_http_types", + "bun_io", + "bun_libdeflate_sys", + "bun_picohttp", + "bun_ptr", + "bun_sys", + "bun_threading", + "bun_url", + "bun_uws", + "bun_wyhash", + "bun_zlib", + "bun_zstd", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_http_types" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_collections", + "bun_core", + "bun_url", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_ini" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_api", + "bun_ast", + "bun_base64", + "bun_collections", + "bun_core", + "bun_dotenv", + "bun_install_types", + "bun_js_parser", + "bun_parsers", + "bun_sys", + "bun_url", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_install" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_analytics", + "bun_ast", + "bun_base64", + "bun_bunfig", + "bun_clap", + "bun_collections", + "bun_core", + "bun_crash_handler", + "bun_dns", + "bun_dotenv", + "bun_event_loop", + "bun_glob", + "bun_http", + "bun_ini", + "bun_install_types", + "bun_io", + "bun_js_parser", + "bun_js_printer", + "bun_libarchive", + "bun_libdeflate_sys", + "bun_options_types", + "bun_parsers", + "bun_patch", + "bun_paths", + "bun_perf", + "bun_picohttp", + "bun_ptr", + "bun_resolver", + "bun_semver", + "bun_sha_hmac", + "bun_simdutf_sys", + "bun_spawn", + "bun_sys", + "bun_threading", + "bun_transpiler", + "bun_url", + "bun_uws", + "bun_which", + "bun_wyhash", + "bun_zlib", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_install_types" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_ast", + "bun_collections", + "bun_core", + "bun_semver", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_io" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_collections", + "bun_core", + "bun_dispatch", + "bun_errno", + "bun_opaque", + "bun_paths", + "bun_ptr", + "bun_spawn_sys", + "bun_sys", + "bun_threading", + "bun_uws_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_js_parser" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bumpalo", + "bun_alloc", + "bun_ast", + "bun_base64", + "bun_collections", + "bun_core", + "bun_crash_handler", + "bun_dispatch", + "bun_highway", + "bun_io", + "bun_options_types", + "bun_paths", + "bun_ptr", + "bun_url", + "bun_wyhash", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "smallvec", + "strum", + "typed-arena", +] + +[[package]] +name = "bun_js_printer" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bumpalo", + "bun_alloc", + "bun_ast", + "bun_collections", + "bun_core", + "bun_crash_handler", + "bun_io", + "bun_options_types", + "bun_paths", + "bun_ptr", + "bun_sourcemap", + "bun_sys", + "bun_wyhash", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "typed-arena", +] + +[[package]] +name = "bun_jsc" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_analytics", + "bun_api", + "bun_ast", + "bun_base64", + "bun_boringssl", + "bun_bundler", + "bun_clap", + "bun_collections", + "bun_core", + "bun_crash_handler", + "bun_dotenv", + "bun_event_loop", + "bun_hash", + "bun_http", + "bun_http_types", + "bun_install", + "bun_io", + "bun_js_parser", + "bun_js_printer", + "bun_jsc_macros", + "bun_opaque", + "bun_options_types", + "bun_paths", + "bun_ptr", + "bun_resolve_builtins", + "bun_resolver", + "bun_s3_signing", + "bun_sha_hmac", + "bun_simdutf_sys", + "bun_sourcemap", + "bun_spawn", + "bun_sys", + "bun_threading", + "bun_transpiler", + "bun_url", + "bun_uws", + "bun_watcher", + "bun_wyhash", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_jsc_macros" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bun_libarchive" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_collections", + "bun_core", + "bun_opaque", + "bun_paths", + "bun_sys", + "bun_wyhash", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_libdeflate_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_opaque", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_libuv_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "bun_windows_sys", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_lolhtml_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "bun_opaque", + "const_format", + "enum-map", + "enumset", + "libc", + "lol_html_c_api", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_md" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_collections", + "bun_core", + "bun_paths", + "bun_sys", + "bun_url", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_mimalloc_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_opaque", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_opaque" +version = "0.0.0" + +[[package]] +name = "bun_options_types" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_ast", + "bun_collections", + "bun_core", + "bun_dotenv", + "bun_install_types", + "bun_libarchive", + "bun_paths", + "bun_semver", + "bun_sys", + "bun_url", + "bun_wyhash", + "bun_zlib", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_output" +version = "0.0.0" +dependencies = [ + "bun_core", +] + +[[package]] +name = "bun_output_tags" +version = "0.0.0" + +[[package]] +name = "bun_parsers" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bumpalo", + "bun_alloc", + "bun_ast", + "bun_collections", + "bun_core", + "bun_highway", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", + "typed-arena", +] + +[[package]] +name = "bun_patch" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_collections", + "bun_core", + "bun_event_loop", + "bun_paths", + "bun_spawn", + "bun_sys", + "bun_which", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_paths" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_core", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_perf" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "bun_paths", + "bun_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_picohttp" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_ptr" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_core", + "bun_core_macros", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_resolve_builtins" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_ast", + "bun_collections", + "bun_core", + "bun_options_types", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_resolver" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bumpalo", + "bun_alloc", + "bun_analytics", + "bun_ast", + "bun_base64", + "bun_collections", + "bun_core", + "bun_crash_handler", + "bun_dotenv", + "bun_glob", + "bun_hash", + "bun_http_types", + "bun_install_types", + "bun_js_parser", + "bun_options_types", + "bun_parsers", + "bun_paths", + "bun_perf", + "bun_ptr", + "bun_resolve_builtins", + "bun_semver", + "bun_sys", + "bun_threading", + "bun_url", + "bun_watcher", + "bun_wyhash", + "bun_zstd", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_router" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_ast", + "bun_collections", + "bun_core", + "bun_http_types", + "bun_options_types", + "bun_paths", + "bun_ptr", + "bun_resolver", + "bun_sys", + "bun_url", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_s3_signing" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_base64", + "bun_boringssl_sys", + "bun_collections", + "bun_core", + "bun_http_types", + "bun_picohttp", + "bun_ptr", + "bun_sha_hmac", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_safety" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_core", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_semver" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_collections", + "bun_core", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_sha_hmac" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_boringssl", + "bun_boringssl_sys", + "bun_core", + "bun_opaque", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_simdutf_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_sourcemap" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bumpalo", + "bun_alloc", + "bun_ast", + "bun_base64", + "bun_collections", + "bun_core", + "bun_io", + "bun_opaque", + "bun_parsers", + "bun_paths", + "bun_ptr", + "bun_semver", + "bun_sys", + "bun_url", + "bun_zstd", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "smallvec", + "strum", + "typed-arena", +] + +[[package]] +name = "bun_spawn" +version = "0.0.0" +dependencies = [ + "bstr", + "bun_analytics", + "bun_core", + "bun_crash_handler", + "bun_dispatch", + "bun_event_loop", + "bun_io", + "bun_opaque", + "bun_output", + "bun_ptr", + "bun_spawn_sys", + "bun_sys", + "bun_threading", + "bun_which", + "libc", + "scopeguard", +] + +[[package]] +name = "bun_spawn_sys" +version = "0.0.0" +dependencies = [ + "bstr", + "bun_analytics", + "bun_core", + "bun_libuv_sys", + "bun_sys", + "bun_windows_sys", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_standalone_graph" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_ast", + "bun_bundler", + "bun_collections", + "bun_core", + "bun_dotenv", + "bun_exe_format", + "bun_http", + "bun_io", + "bun_js_parser", + "bun_libarchive", + "bun_opaque", + "bun_options_types", + "bun_parsers", + "bun_paths", + "bun_perf", + "bun_resolver", + "bun_sourcemap", + "bun_sys", + "bun_threading", + "bun_url", + "bun_zlib", + "bun_zstd", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_core", + "bun_errno", + "bun_libuv_sys", + "bun_opaque", + "bun_output", + "bun_paths", + "bun_windows_sys", + "bun_wyhash", + "bytemuck", + "const_format", + "enum-map", + "enumset", + "libc", + "memchr", + "rustix", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_threading" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_collections", + "bun_core", + "bun_ptr", + "bun_safety", + "bun_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_transpiler" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_bundler", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_url" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_collections", + "bun_core", + "bun_paths", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_uws" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_boringssl", + "bun_core", + "bun_jsc_macros", + "bun_opaque", + "bun_ptr", + "bun_uws_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_uws_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_boringssl_sys", + "bun_core", + "bun_errno", + "bun_http_types", + "bun_libuv_sys", + "bun_opaque", + "bun_paths", + "bun_windows_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", + "thiserror", +] + +[[package]] +name = "bun_watcher" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_collections", + "bun_core", + "bun_paths", + "bun_ptr", + "bun_sys", + "bun_threading", + "bun_wyhash", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_which" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "bun_paths", + "bun_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_windows_sys" +version = "0.0.0" + +[[package]] +name = "bun_wyhash" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_zlib" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_alloc", + "bun_collections", + "bun_core", + "bun_io", + "bun_zlib_sys", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_zlib_sys" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bun_zstd" +version = "0.0.0" +dependencies = [ + "bitflags", + "bstr", + "bun_core", + "bun_opaque", + "const_format", + "enum-map", + "enumset", + "libc", + "scopeguard", + "strum", +] + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "const_format" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" +dependencies = [ + "const_format_proc_macros", + "konst", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "cssparser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "enumset" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839c4174b41e75c8f7306110b2c51996a293b8d1d850edd529011841d9fede7d" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "log" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" + +[[package]] +name = "lol_html" +version = "2.7.2" +dependencies = [ + "bitflags", + "cfg-if", + "cssparser", + "encoding_rs", + "foldhash", + "hashbrown 0.16.1", + "memchr", + "mime", + "precomputed-hash", + "selectors", + "thiserror", +] + +[[package]] +name = "lol_html_c_api" +version = "1.3.1" +dependencies = [ + "encoding_rs", + "libc", + "lol_html", + "thiserror", +] + +[[package]] +name = "marked_array_buffer_ownership_soundness_fixture" +version = "0.0.0" +dependencies = [ + "bun_jsc", +] + +[[package]] +name = "memchr" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "selectors" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feef350c36147532e1b79ea5c1f3791373e61cbd9a6a2615413b3807bb164fb7" +dependencies = [ + "bitflags", + "cssparser", + "derive_more", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "servo_arc" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/test/regression/marked-array-buffer-ownership-soundness-fixture/Cargo.toml b/test/regression/marked-array-buffer-ownership-soundness-fixture/Cargo.toml new file mode 100644 index 00000000000..51243f573c3 --- /dev/null +++ b/test/regression/marked-array-buffer-ownership-soundness-fixture/Cargo.toml @@ -0,0 +1,26 @@ +# Compile-only fixture for test/regression/marked-array-buffer-ownership-soundness.test.ts +# — verifies that `bun_jsc::MarkedArrayBuffer` has no safe constructor that +# adopts a borrowed `&mut [u8]` as an allocator-owned buffer (issue #31969). +# The test invokes `cargo check` on this crate and asserts the expected +# resolution error fires. +# +# Detached from the parent workspace so `cargo check` on the top-level +# doesn't pull it in (it intentionally fails to compile). +# `Cargo.lock` is committed so the test driver pins the transitive dep +# graph with `--locked` — keeps the compile-fail check hermetic rather +# than re-resolving `bun_jsc`'s deps against crates.io on every run. +# If a dependency changes anywhere in bun_jsc's graph, regenerate it: +# (cd test/regression/marked-array-buffer-ownership-soundness-fixture && cargo update) +[workspace] + +[package] +name = "marked_array_buffer_ownership_soundness_fixture" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +bun_jsc = { path = "../../../src/jsc" } + +[lib] +path = "src/lib.rs" diff --git a/test/regression/marked-array-buffer-ownership-soundness-fixture/src/lib.rs b/test/regression/marked-array-buffer-ownership-soundness-fixture/src/lib.rs new file mode 100644 index 00000000000..a4255ce3a66 --- /dev/null +++ b/test/regression/marked-array-buffer-ownership-soundness-fixture/src/lib.rs @@ -0,0 +1,19 @@ +//! Compile-fail fixture for +//! `test/regression/marked-array-buffer-ownership-soundness.test.ts`. +//! +//! This crate must NOT compile. `MarkedArrayBuffer` has no safe constructor +//! that adopts a borrowed `&mut [u8]` as allocator-owned storage — ownership +//! transfer requires a `Box<[u8]>` (`MarkedArrayBuffer::from_owned_bytes`). +//! +//! Before the fix for issue #31969, `MarkedArrayBuffer::from_bytes` accepted +//! exactly this code: it stored the stack slice's pointer with +//! `owns_buffer: true`, and `destroy()` then freed the stack address with the +//! default allocator. + +use bun_jsc::{JSType, MarkedArrayBuffer}; + +pub fn free_a_stack_buffer() { + let mut bytes = [0u8; 1]; + let mut buffer = MarkedArrayBuffer::from_bytes(&mut bytes, JSType::Uint8Array); + buffer.destroy(); +} diff --git a/test/regression/marked-array-buffer-ownership-soundness.test.ts b/test/regression/marked-array-buffer-ownership-soundness.test.ts new file mode 100644 index 00000000000..f4ca90ab3d5 --- /dev/null +++ b/test/regression/marked-array-buffer-ownership-soundness.test.ts @@ -0,0 +1,72 @@ +// Compile-time soundness test for `bun_jsc::MarkedArrayBuffer`'s ownership +// boundary. Not a true regression (the hole was latent since the type was +// introduced, never "worked" in a prior release — see issue #31969), so it +// lives in test/regression/ rather than test/regression/issue/ per +// test/CLAUDE.md. +// +// `MarkedArrayBuffer::from_bytes(&mut [u8])` was a safe, public constructor +// that marked an arbitrary borrowed slice as allocator-owned +// (`owns_buffer: true`); the safe `destroy()` later freed that pointer with +// the default allocator. Safe code could therefore free a stack buffer: +// +// let mut bytes = [0u8; 1]; +// let mut buffer = MarkedArrayBuffer::from_bytes(&mut bytes, JSType::Uint8Array); +// buffer.destroy(); // frees the stack address +// +// The fix replaces it with `from_owned_bytes(Box<[u8]>, ..)` so the ownership +// transfer is enforced by the type system. The companion `-fixture/` crate +// contains exactly the unsound pattern above; with the fix in place +// `cargo check` rejects it (E0599: `from_bytes` no longer exists on +// `MarkedArrayBuffer`). If a safe borrowed-slice constructor is ever +// reintroduced, the fixture compiles again and this test fails. + +import { spawn, which } from "bun"; +import { expect, test } from "bun:test"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; + +const cargo = which("cargo"); +const fixtureDir = join(import.meta.dir, "marked-array-buffer-ownership-soundness-fixture"); +// bun_jsc's build script needs the cppbind codegen output (produced by +// `bun bd` / `bun run build`); skip on runners that only have a prebuilt +// bun binary and no build tree. +const codegenDir = join(import.meta.dir, "../../build/debug/codegen"); +const hasCodegen = existsSync(join(codegenDir, "cpp.rs")); + +test.skipIf(!cargo || !hasCodegen)( + "MarkedArrayBuffer cannot adopt a borrowed slice as owned storage", + { timeout: 10 * 60 * 1000 }, // first run type-checks bun_jsc's dep graph; cached after + async () => { + await using proc = spawn({ + // `--locked` so the fixture's committed Cargo.lock pins the transitive + // dep graph — the assertions below only fire for the intended + // resolution error, not for registry drift. + cmd: [cargo!, "check", "--locked", "--message-format=short"], + cwd: fixtureDir, + env: { + ...process.env, + CARGO_TERM_COLOR: "never", + BUN_CODEGEN_DIR: codegenDir, + }, + stdout: "pipe", + stderr: "pipe", + }); + + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + const out = stdout + stderr; + + // A dep change anywhere in bun_jsc's graph invalidates the fixture's + // committed lockfile; surface the regeneration command instead of an + // opaque assertion diff. + if (out.includes("--locked was passed")) { + throw new Error(`fixture Cargo.lock is stale; run:\n (cd ${fixtureDir} && cargo update)\n\n${out}`); + } + + // The unsound pattern must fail to resolve. Check the content first, + // exit code last — a missing-text failure (which prints cargo's output) + // is a more useful signal than "cargo returned 0". + expect(out).toContain("E0599"); + expect(out).toContain("from_bytes"); + expect(exitCode).toBe(101); // cargo check exits 101 on compile errors + }, +);