Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/bun_core/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,10 @@ pub(crate) mod strings_impl {
break;
}
Some(i) => {
debug_assert!(
rest[i] >= 0x80,
"first_non_ascii_usize pointed at an ASCII byte"
);
list.extend_from_slice(&rest[..i]);
rest = &rest[i..];
while let Some(&c) = rest.first() {
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/bin_entry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ pub(crate) unsafe extern "C" fn main(argc: c_int, argv: *const *const c_char) ->
// 1. Crash handler first so anything below gets a usable trace.
bun_crash_handler::init();

// Before the first string conversion: simdutf's CPUID dispatch may have
// picked a stub that returns 0 for every call.
Comment thread
robobun marked this conversation as resolved.
Resolved
bun_simdutf_sys::simdutf::init();

use_mimalloc_in_dependencies();

// SIGPIPE/SIGXFSZ → SIG_IGN.
Expand Down
18 changes: 18 additions & 0 deletions src/simdutf_sys/bun-simdutf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ typedef struct SIMDUTFResult {

extern "C" {

// When CPUID advertises none of the compiled-in kernels (QEMU's default CPU
// model hides SSE4.2 that the host executes), simdutf installs a stub whose
// every method returns 0 / false. WTF builds simdutf without the scalar
// fallback, so pick the last kernel in the priority-ordered list: on x64 that
// is westmere, the same -march=nehalem baseline the whole binary runs.
Comment thread
robobun marked this conversation as resolved.
Resolved
void simdutf__init()
{
if (simdutf::get_active_implementation()->name() != "unsupported")
return;

const simdutf::implementation* least_demanding = nullptr;
for (const simdutf::implementation* impl : simdutf::get_available_implementations())
least_demanding = impl;

if (least_demanding)
simdutf::get_active_implementation() = least_demanding;
}

bool simdutf__validate_utf8(const char* buf, size_t len)
{
return simdutf::validate_utf8(buf, len);
Expand Down
7 changes: 7 additions & 0 deletions src/simdutf_sys/simdutf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl Status {
}

unsafe extern "C" {
safe fn simdutf__init();
pub(crate) fn simdutf__validate_utf8(buf: *const u8, len: usize) -> bool;
pub(crate) fn simdutf__validate_utf8_with_errors(buf: *const u8, len: usize) -> SIMDUTFResult;
pub fn simdutf__validate_ascii(buf: *const u8, len: usize) -> bool;
Expand Down Expand Up @@ -60,6 +61,12 @@ unsafe extern "C" {
pub fn simdutf__utf8_length_from_latin1(input: *const u8, length: usize) -> usize;
}

/// Replaces simdutf's "unsupported" stub (every call returns 0 / false) with a
/// compiled-in kernel. Call once at process start, before any thread.
Comment thread
robobun marked this conversation as resolved.
Resolved
pub fn init() {
simdutf__init();
}

pub mod validate {
use super::*;

Expand Down
26 changes: 26 additions & 0 deletions test/regression/issue/41361.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { expect, test } from "bun:test";
import { bunEnv, bunExe, tempDir } from "harness";

// simdutf picks its SIMD kernel by CPUID at first use. When no compiled-in
// kernel matches (QEMU's default CPU model hides SSE4.2), it installs a stub
// whose every call returns 0 or false. SIMDUTF_FORCE_IMPLEMENTATION with an
// unknown name installs the same stub on any machine. Bun used to spin forever
// in a Latin-1 to UTF-8 loop on the first ASCII string longer than 32 bytes,
// which is the entry point path, before it opened the entry file.
test("bun starts when simdutf finds no supported kernel", async () => {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
using dir = tempDir("simdutf-no-supported-kernel", {
"entry-file-with-a-name-longer-than-thirty-two-bytes.mjs": `console.log("ok");`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), `${dir}/entry-file-with-a-name-longer-than-thirty-two-bytes.mjs`],
env: { ...bunEnv, SIMDUTF_FORCE_IMPLEMENTATION: "bogus" },
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
expect(stdout).toBe("ok\n");
expect(stderr).toBe("");
expect(proc.signalCode).toBeNull();
expect(exitCode).toBe(0);
Comment thread
robobun marked this conversation as resolved.
Resolved
});
Loading