diff --git a/src/bun_core/tty.rs b/src/bun_core/tty.rs index 29926732e65a..4bf156f91360 100644 --- a/src/bun_core/tty.rs +++ b/src/bun_core/tty.rs @@ -89,7 +89,9 @@ impl RawModeGuard { impl Drop for RawModeGuard { #[inline] fn drop(&mut self) { - let _ = self.state.set_mode(self.fd, Mode::Normal, SetAttrWhen::Drain); + let _ = self + .state + .set_mode(self.fd, Mode::Normal, SetAttrWhen::Drain); } } diff --git a/src/highway/lib.rs b/src/highway/lib.rs index fa4a35fc2d95..fb2ca825210c 100644 --- a/src/highway/lib.rs +++ b/src/highway/lib.rs @@ -10,6 +10,7 @@ unsafe extern "C" { fn highway_count_char(haystack: *const u8, haystack_len: usize, needle: u8) -> usize; + #[cfg(not(miri))] fn highway_memmem( haystack: *const u8, haystack_len: usize, @@ -19,6 +20,7 @@ unsafe extern "C" { // These three return `usize::MAX` for not-found (the empty needle matches at // 0 / `haystack_len` respectively). + #[cfg(not(miri))] fn highway_memrmem( haystack: *const u8, haystack_len: usize, @@ -26,6 +28,7 @@ unsafe extern "C" { needle_len: usize, ) -> usize; + #[cfg(not(miri))] fn highway_memmem16( haystack: *const u16, haystack_len: usize, @@ -33,6 +36,7 @@ unsafe extern "C" { needle_len: usize, ) -> usize; + #[cfg(not(miri))] fn highway_memrmem16( haystack: *const u16, haystack_len: usize, @@ -157,6 +161,31 @@ unsafe extern "C" { /// call into a caller's hot loop (see `pop_last_segment_t` in node/path.rs). const SCALAR_CUTOFF: usize = 16; +/// Miri cannot call foreign functions, and the workspace denies std's search +/// methods everywhere else, so under Miri (`bun run rust:miri`) the search +/// wrappers below take their scalar path at every length. Kernels with no +/// scalar form here (hashing, hex, sourcemaps, lexer scans) stay FFI-only: +/// reaching one from a Miri-tested crate is a loud, immediate error. +#[inline(always)] +fn scalar_only(len: usize) -> bool { + cfg!(miri) || len < SCALAR_CUTOFF +} + +/// Scalar substring search for Miri. Callers have already handled the empty +/// needle and `haystack.len() < needle.len()`. +#[cfg(miri)] +fn scalar_memmem(haystack: &[T], needle: &[T]) -> Option { + (0..=haystack.len() - needle.len()).find(|&i| haystack[i..i + needle.len()] == *needle) +} + +/// Reverse [`scalar_memmem`]: start index of the last occurrence. +#[cfg(miri)] +fn scalar_memrmem(haystack: &[T], needle: &[T]) -> Option { + (0..=haystack.len() - needle.len()) + .rev() + .find(|&i| haystack[i..i + needle.len()] == *needle) +} + /// The single-byte kernels return `haystack_len` for "not found". #[inline(always)] fn found_at(result: usize, haystack_len: usize) -> Option { @@ -168,6 +197,7 @@ fn found_at(result: usize, haystack_len: usize) -> Option { } /// The `mem*mem*` kernels return `usize::MAX` for "not found". +#[cfg(not(miri))] #[inline(always)] fn match_at(result: usize) -> Option { if result == usize::MAX { @@ -179,7 +209,7 @@ fn match_at(result: usize) -> Option { #[inline(always)] pub fn index_of_char(haystack: &[u8], needle: u8) -> Option { - if haystack.len() < SCALAR_CUTOFF { + if scalar_only(haystack.len()) { return haystack.iter().position(|&b| b == needle); } // SAFETY: haystack.ptr/len are a valid readable range. @@ -191,7 +221,7 @@ pub fn index_of_char(haystack: &[u8], needle: u8) -> Option { #[inline(always)] pub fn last_index_of_char(haystack: &[u8], needle: u8) -> Option { - if haystack.len() < SCALAR_CUTOFF { + if scalar_only(haystack.len()) { return haystack.iter().rposition(|&b| b == needle); } // SAFETY: haystack.ptr/len are a valid readable range. @@ -205,7 +235,7 @@ pub fn last_index_of_char(haystack: &[u8], needle: u8) -> Option { /// run of `value`), or `None` if every byte is `value`. #[inline(always)] pub fn index_of_not_char(haystack: &[u8], value: u8) -> Option { - if haystack.len() < SCALAR_CUTOFF { + if scalar_only(haystack.len()) { return haystack.iter().position(|&b| b != value); } // SAFETY: haystack.ptr/len are a valid readable range. @@ -217,7 +247,7 @@ pub fn index_of_not_char(haystack: &[u8], value: u8) -> Option { #[inline(always)] pub fn count_char(haystack: &[u8], needle: u8) -> usize { - if haystack.len() < SCALAR_CUTOFF { + if scalar_only(haystack.len()) { return haystack.iter().filter(|&&b| b == needle).count(); } // SAFETY: haystack.ptr/len are a valid readable range. @@ -232,20 +262,27 @@ pub fn memmem(haystack: &[u8], needle: &[u8]) -> Option { if haystack.len() < needle.len() { return None; } - // SAFETY: both (ptr,len) pairs are valid readable ranges. - let p = unsafe { - highway_memmem( - haystack.as_ptr(), - haystack.len(), - needle.as_ptr(), - needle.len(), - ) - }; - if p.is_null() { - None - } else { - // SAFETY: highway_memmem returns a pointer within `haystack` on success. - Some(unsafe { p.offset_from(haystack.as_ptr()) } as usize) + #[cfg(miri)] + { + scalar_memmem(haystack, needle) + } + #[cfg(not(miri))] + { + // SAFETY: both (ptr,len) pairs are valid readable ranges. + let p = unsafe { + highway_memmem( + haystack.as_ptr(), + haystack.len(), + needle.as_ptr(), + needle.len(), + ) + }; + if p.is_null() { + None + } else { + // SAFETY: highway_memmem returns a pointer within `haystack` on success. + Some(unsafe { p.offset_from(haystack.as_ptr()) } as usize) + } } } @@ -259,18 +296,25 @@ pub fn memrmem(haystack: &[u8], needle: &[u8]) -> Option { if haystack.len() < needle.len() { return None; } - // SAFETY: both (ptr,len) pairs are valid readable ranges. - let result = unsafe { - highway_memrmem( - haystack.as_ptr(), - haystack.len(), - needle.as_ptr(), - needle.len(), - ) - }; - let found = match_at(result); - debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle))); - found + #[cfg(miri)] + { + scalar_memrmem(haystack, needle) + } + #[cfg(not(miri))] + { + // SAFETY: both (ptr,len) pairs are valid readable ranges. + let result = unsafe { + highway_memrmem( + haystack.as_ptr(), + haystack.len(), + needle.as_ptr(), + needle.len(), + ) + }; + let found = match_at(result); + debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle))); + found + } } #[inline(always)] @@ -281,18 +325,25 @@ pub fn memmem16(haystack: &[u16], needle: &[u16]) -> Option { if haystack.len() < needle.len() { return None; } - // SAFETY: both (ptr,len) pairs are valid readable ranges (`&[u16]` is 2-byte aligned). - let result = unsafe { - highway_memmem16( - haystack.as_ptr(), - haystack.len(), - needle.as_ptr(), - needle.len(), - ) - }; - let found = match_at(result); - debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle))); - found + #[cfg(miri)] + { + scalar_memmem(haystack, needle) + } + #[cfg(not(miri))] + { + // SAFETY: both (ptr,len) pairs are valid readable ranges (`&[u16]` is 2-byte aligned). + let result = unsafe { + highway_memmem16( + haystack.as_ptr(), + haystack.len(), + needle.as_ptr(), + needle.len(), + ) + }; + let found = match_at(result); + debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle))); + found + } } /// Start index of the last occurrence of `needle`. An empty needle matches at @@ -305,18 +356,25 @@ pub fn memrmem16(haystack: &[u16], needle: &[u16]) -> Option { if haystack.len() < needle.len() { return None; } - // SAFETY: both (ptr,len) pairs are valid readable ranges (`&[u16]` is 2-byte aligned). - let result = unsafe { - highway_memrmem16( - haystack.as_ptr(), - haystack.len(), - needle.as_ptr(), - needle.len(), - ) - }; - let found = match_at(result); - debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle))); - found + #[cfg(miri)] + { + scalar_memrmem(haystack, needle) + } + #[cfg(not(miri))] + { + // SAFETY: both (ptr,len) pairs are valid readable ranges (`&[u16]` is 2-byte aligned). + let result = unsafe { + highway_memrmem16( + haystack.as_ptr(), + haystack.len(), + needle.as_ptr(), + needle.len(), + ) + }; + let found = match_at(result); + debug_assert!(found.is_none_or(|i| haystack[i..].starts_with(needle))); + found + } } #[inline(always)] @@ -461,7 +519,7 @@ pub fn index_of_any_char(haystack: &[u8], chars: &[u8]) -> Option { return None; } debug_assert!(chars.len() >= 2 && chars.len() <= 16); - if haystack.len() < SCALAR_CUTOFF { + if scalar_only(haystack.len()) { return haystack.iter().position(|b| chars.contains(b)); } @@ -503,7 +561,7 @@ pub fn last_index_of_any_char(haystack: &[u8], chars: &[u8]) -> Option { return None; } debug_assert!(chars.len() >= 2 && chars.len() <= 16); - if haystack.len() < SCALAR_CUTOFF { + if scalar_only(haystack.len()) { return haystack.iter().rposition(|b| chars.contains(b)); } diff --git a/src/md/ansi_renderer.rs b/src/md/ansi_renderer.rs index b35a5419d7c0..0deed8793f5d 100644 --- a/src/md/ansi_renderer.rs +++ b/src/md/ansi_renderer.rs @@ -2535,7 +2535,11 @@ fn probe_kitty_graphics() -> bool { Err(_) => return false, }; let mut tty_state = bun_core::tty::State::new(); - let _ = tty_state.set_mode(0, bun_core::tty::Mode::Raw, bun_core::tty::SetAttrWhen::Drain); + let _ = tty_state.set_mode( + 0, + bun_core::tty::Mode::Raw, + bun_core::tty::SetAttrWhen::Drain, + ); let _restore = scopeguard::guard((saved_termios, tty_state), |(saved, mut state)| { if bun_sys::posix::tcsetattr(0, bun_sys::posix::TCSA::Now, &saved).is_err() { let _ = state.set_mode( diff --git a/src/parsers/yaml.rs b/src/parsers/yaml.rs index af318a3d03d1..738bec3d395e 100644 --- a/src/parsers/yaml.rs +++ b/src/parsers/yaml.rs @@ -3311,6 +3311,8 @@ impl CollectionData for E::Object { } impl<'i, Enc: Encoding> Parser<'i, Enc> { + // By value so binding consumes the `#[must_use]` anchor token. + #[allow(clippy::needless_pass_by_value)] fn bind_anchor(&mut self, anchor: PendingAnchor, node: Expr) -> Result<(), AllocError> { self.anchors .put(Enc::key_bytes(anchor.name.slice(self.input)), node) diff --git a/src/runtime/bake/bake_body.rs b/src/runtime/bake/bake_body.rs index 3e4cc72b47bb..cdd8ab2dadcd 100644 --- a/src/runtime/bake/bake_body.rs +++ b/src/runtime/bake/bake_body.rs @@ -10,8 +10,8 @@ use core::ptr::NonNull; use bun_alloc::Arena; // = bumpalo::Bump use bun_collections::ArrayHashMap; use bun_core::Output; -use bun_jsc::{JSGlobalObject, JSValue, JsError, JsResult, ZigStringSlice}; use bun_core::{ZStr, strings}; +use bun_jsc::{JSGlobalObject, JSValue, JsError, JsResult, ZigStringSlice}; use bun_options_types::schema as bun_schema; use bun_paths::{self as paths, PathBuffer}; diff --git a/src/runtime/server/server_body.rs b/src/runtime/server/server_body.rs index 309f72865893..2867551551ae 100644 --- a/src/runtime/server/server_body.rs +++ b/src/runtime/server/server_body.rs @@ -492,7 +492,10 @@ pub mod BunInfo { // `JSON.toAST(allocator, BunInfo, info)` — hand-expanded: let platform_props = bun_alloc::AstAlloc::vec_from_iter([ prop(b"os", str_expr(os_tag_name(info.platform.os))), - prop(b"arch", str_expr(arch_tag_name(bun_core::Environment::ARCH))), + prop( + b"arch", + str_expr(arch_tag_name(bun_core::Environment::ARCH)), + ), prop(b"version", str_expr(info.platform.version)), ]); let platform_expr = Expr::init( diff --git a/src/runtime/socket/uws_handlers.rs b/src/runtime/socket/uws_handlers.rs index 5bc312e75db5..cbf24a3dce5d 100644 --- a/src/runtime/socket/uws_handlers.rs +++ b/src/runtime/socket/uws_handlers.rs @@ -406,7 +406,7 @@ where { // `ns` is the live heap `NewSocket` stashed by `on_create`. The // `on_*` handlers may free it, so they take `ThisPtr`, never `&mut`. - swallow(api::NewSocket::on_close(ns, wrap::(s), code, reason)); + api::NewSocket::on_close(ns, wrap::(s), code, reason); } } fn on_data_no_ext(s: *mut us_socket_t, data: &[u8]) { @@ -436,12 +436,7 @@ where fn on_handshake_no_ext(s: *mut us_socket_t, ok: bool, err: us_bun_verify_error_t) { if let Some(ns) = *us_socket_t::opaque_mut(s).ext::>>>() { - swallow(api::NewSocket::on_handshake( - ns, - wrap::(s), - ok as i32, - err, - )); + api::NewSocket::on_handshake(ns, wrap::(s), ok as i32, err); } } } diff --git a/test/tsconfig.json b/test/tsconfig.json index 94ca402ee15d..f0c1ebc8d00c 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -40,6 +40,7 @@ "__snapshots__", // bun snapshots (toMatchSnapshot) "./snapshots", "./js/deno", - "./node.js" // entire node.js upstream repository + "./node.js", // entire node.js upstream repository + "regression/issue/14477/*-mismatch.tsx" // deliberately-mismatched JSX, the test asserts the parse error ] } diff --git a/tsconfig.json b/tsconfig.json index 6d7eece9e746..bcf922bf74b6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,7 @@ }, "references": [ { "path": "./src" }, - { "path": "./src/bake" }, + { "path": "./src/runtime/bake" }, { "path": "./src/js" }, { "path": "./test" }, { "path": "./packages/bun-types" }