Skip to content
Merged
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
14 changes: 12 additions & 2 deletions src/crash_handler/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,12 @@ mod draft {
.store(handle as *mut core::ffi::c_void, Ordering::Relaxed);
}
}
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "android", target_os = "freebsd"))]
#[cfg(any(
target_os = "macos",
target_os = "linux",
target_os = "android",
target_os = "freebsd"
))]
{
reset_on_posix();
}
Expand Down Expand Up @@ -2907,7 +2912,12 @@ mod draft {
let _ = spawn_result;
let _ = url;
}
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "android", target_os = "freebsd"))]
#[cfg(any(
target_os = "macos",
target_os = "linux",
target_os = "android",
target_os = "freebsd"
))]
{
let mut buf = bun_core::PathBuffer::default();
let mut buf2 = bun_core::PathBuffer::default();
Expand Down
14 changes: 12 additions & 2 deletions src/errno/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,12 @@ mod errno_name_tests {
assert_eq!(Error::from_errno(0), Error::UNEXPECTED);
assert_eq!(Error::from_errno(9999), Error::UNEXPECTED);
// errno 11 is platform-specific: EAGAIN on linux/windows, EDEADLK on darwin/bsd.
#[cfg(any(target_os = "linux", target_os = "android", windows, target_family = "wasm"))]
#[cfg(any(
target_os = "linux",
target_os = "android",
windows,
target_family = "wasm"
))]
{
assert_eq!(Error::from_errno(11), Error::intern("EAGAIN"));
assert_eq!(Error::from_errno(104), Error::intern("ECONNRESET"));
Expand Down Expand Up @@ -464,7 +469,12 @@ mod errno_name_tests {
coreutils_error_map::get(2),
Some("No such file or directory")
);
#[cfg(any(target_os = "linux", target_os = "android", windows, target_family = "wasm"))]
#[cfg(any(
target_os = "linux",
target_os = "android",
windows,
target_family = "wasm"
))]
assert_eq!(
coreutils_error_map::get(11),
Some("Resource temporarily unavailable")
Expand Down
7 changes: 6 additions & 1 deletion src/perf/tracy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,12 @@ fn dlsym<T: Copy>(symbol: &'static core::ffi::CStr) -> Option<T> {
];
#[cfg(windows)]
const PATHS_TO_TRY: &[&core::ffi::CStr] = &[c"tracy.dll"];
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "android", windows)))]
#[cfg(not(any(
target_os = "macos",
target_os = "linux",
target_os = "android",
windows
)))]
const PATHS_TO_TRY: &[&core::ffi::CStr] = &[];

// TODO(port): RTLD flags — Zig used `@bitCast(@as(i32, -2))` on
Expand Down
10 changes: 9 additions & 1 deletion src/resolver/package_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2758,9 +2758,17 @@ impl<'a> ESModule<'a> {
},
};
} else {
// PORT NOTE: Zig used `.auto` here, carried over as a
// latent Windows bug (#30839): this branch runs when an
// `imports` target is itself a package specifier
// (e.g. `@myproject/resolver`) that we hand back to
// package-resolve. Per the Node.js packages spec these
// are URL-like specifiers and must keep forward slashes;
// `Auto` normalizes them to `\` on Windows and the
// scoped-name match fails, falling through to `main`.
let parts2 = [str, subpath];
let result = resolve_path::resolve_path::join_string_buf::<
resolve_path::platform::Auto,
resolve_path::platform::Posix,
>(
&mut resolve_target_buf2.0, &parts2
);
Expand Down
5 changes: 4 additions & 1 deletion src/runtime/cli/Arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,10 @@ pub const BASE_RUNTIME_TRANSPILER_PARAMS: &[ParamType] =
// built with `comptime_table!(.., cold)` and stay in plain `.rodata`, where
// `src/startup.order` can still cluster the ones a sampled cold path actually
// hits without weighing down the `.rodata.startup` fault-around window.
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".rodata.startup"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".rodata.startup")
)]
pub static AUTO_TABLE: &clap::ConvertedTable = clap::comptime_table!(AUTO_PARAMS);
pub static RUN_TABLE: &clap::ConvertedTable = clap::comptime_table!(RUN_PARAMS, cold);
pub static BUILD_TABLE: &clap::ConvertedTable = clap::comptime_table!(BUILD_PARAMS, cold);
Expand Down
45 changes: 36 additions & 9 deletions src/runtime/cli/run_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,10 @@ Full documentation is available at <magenta>https://bun.com/docs/cli/run<r>
/// not share `.text` pages with the hot `bun run <script>` dispatch path.
#[cold]
#[inline(never)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".text.unlikely"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".text.unlikely")
)]
fn configure_run_transpiler_linker(this_transpiler: &mut Transpiler<'static>) {
this_transpiler.resolver.opts.load_tsconfig_json = true;
this_transpiler.options.load_tsconfig_json = true;
Expand Down Expand Up @@ -870,7 +873,10 @@ Full documentation is available at <magenta>https://bun.com/docs/cli/run<r>
/// initializing JSC.
#[cold]
#[inline(never)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".text.unlikely"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".text.unlikely")
)]
fn boot_bun_shell(
ctx: &mut ContextData,
entry_path: &[u8],
Expand Down Expand Up @@ -1669,7 +1675,10 @@ fn log_clear_msgs(vm: &mut VirtualMachine) {

#[cold]
#[inline(never)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".text.unlikely"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".text.unlikely")
)]
fn dump_build_error(vm: &mut VirtualMachine) {
Output::flush();
if let Some(log) = vm.log {
Expand All @@ -1689,7 +1698,10 @@ fn dump_build_error(vm: &mut VirtualMachine) {
/// `.text.hot` fault-around window the `require('fs')` startup path pulls in.
#[cold]
#[inline(never)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".text.unlikely"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".text.unlikely")
)]
fn exit_with_unhandled_note(vm: &mut VirtualMachine) -> ! {
vm.exit_handler.exit_code = 1;
vm.on_exit();
Expand All @@ -1703,7 +1715,10 @@ fn exit_with_unhandled_note(vm: &mut VirtualMachine) -> ! {
/// Cold `Err(err)` arm of `vm.load_entry_point` in `Run::start`.
#[cold]
#[inline(never)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".text.unlikely"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".text.unlikely")
)]
fn entry_point_load_failed(vm: &mut VirtualMachine, err: &bun_core::Error) -> ! {
if log_has_msgs(vm) {
dump_build_error(vm);
Expand All @@ -1722,7 +1737,10 @@ fn entry_point_load_failed(vm: &mut VirtualMachine, err: &bun_core::Error) -> !
/// exit: bump the exit code and print the sourcemap note + version string.
#[cold]
#[inline(never)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".text.unlikely"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".text.unlikely")
)]
fn print_unhandled_version_note(vm: &mut VirtualMachine) {
vm.exit_handler.exit_code = 1;
bun_sourcemap::SavedSourceMap::MissingSourceMapNoteInfo::print();
Expand Down Expand Up @@ -1762,7 +1780,10 @@ impl RunCommand {
/// `.text.hot` fault-around window the `require('fs')` startup path pulls in.
#[cold]
#[inline(never)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".text.unlikely"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".text.unlikely")
)]
fn boot_failed_exit(ctx: &mut ContextData, display_name: &[u8], err: &bun_core::Error) -> ! {
// SAFETY: `ctx.log` was set in `create_context_data` (single-threaded
// CLI startup) and is process-lifetime.
Expand Down Expand Up @@ -3022,7 +3043,10 @@ impl RunCommand {

#[cold]
#[inline(never)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".text.unlikely"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".text.unlikely")
)]
fn exec_as_if_node_missing_script() -> ! {
Output::err_generic(
"Missing script to execute. Bun's provided 'node' cli wrapper does not support a repl.",
Expand All @@ -3033,7 +3057,10 @@ impl RunCommand {

#[cold]
#[inline(never)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), unsafe(link_section = ".text.unlikely"))]
#[cfg_attr(
any(target_os = "linux", target_os = "android"),
unsafe(link_section = ".text.unlikely")
)]
fn exec_as_if_node_boot_failed(
ctx: &mut ContextData,
basename: &[u8],
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cli/upgrade_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,12 @@ impl UpgradeCommand {
{
"powershell -c 'irm bun.sh/install.ps1|iex'"
}
#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "windows")))]
#[cfg(not(any(
target_os = "linux",
target_os = "android",
target_os = "macos",
target_os = "windows"
)))]
{
// TODO(port): Environment.os.displayString() at comptime
"(TODO: Install script for this platform)"
Expand Down
7 changes: 4 additions & 3 deletions src/runtime/jsc_hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4499,13 +4499,14 @@ pub(crate) fn resolve_embedded_file_to_buf(
// Spec ModuleLoader.zig:43-45 — `tmpname(extname, buf, bun.hash(file.name))`.
let mut tmpname_buf = bun_paths::path_buffer_pool::get();
let tmpfilename =
Fs::FileSystem::tmpname(extname, &mut tmpname_buf[..], bun_wyhash::hash(file_name))
.ok()?;
Fs::FileSystem::tmpname(extname, &mut tmpname_buf[..], bun_wyhash::hash(file_name)).ok()?;

// Spec ModuleLoader.zig:47 — `bun.fs.FileSystem.instance.tmpdir()`.
// SAFETY: `FileSystem::instance()` returns the process-global singleton
// pointer (initialized at startup).
let tmpdir = (unsafe { &mut *Fs::FileSystem::instance() }).tmpdir().ok()?;
let tmpdir = (unsafe { &mut *Fs::FileSystem::instance() })
.tmpdir()
.ok()?;
let tmpdir_fd: bun_sys::Fd = tmpdir.fd;

// Spec ModuleLoader.zig:50-51 — `bun.Tmpfile.create(tmpdir, tmpfilename)`.
Expand Down
12 changes: 10 additions & 2 deletions src/runtime/webview/ChromeProcess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,10 @@ fn find_playwright_shell() -> Option<ZBox> {
}

// Fall back to the non-cft linux arm64 layout.
#[cfg(all(any(target_os = "linux", target_os = "android"), target_arch = "aarch64"))]
#[cfg(all(
any(target_os = "linux", target_os = "android"),
target_arch = "aarch64"
))]
{
let bin_parts2: [&[u8]; 3] = [
cache_dir,
Expand Down Expand Up @@ -633,7 +636,12 @@ fn read_dev_tools_active_port(out_buf: &mut Vec<u8>) -> Option<()> {
b"BraveSoftware\\Brave-Browser\\User Data\\DevToolsActivePort",
b"Microsoft\\Edge\\User Data\\DevToolsActivePort",
];
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "android", windows)))]
#[cfg(not(any(
target_os = "macos",
target_os = "linux",
target_os = "android",
windows
)))]
let candidates: &[&[u8]] = &[];

let mut path_buf = path_buffer_pool::get();
Expand Down
11 changes: 9 additions & 2 deletions src/spawn/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3224,7 +3224,10 @@ mod spawn_process_body {
// that are read *after* the wait, so falling through to the memfd block
// below is required.
let status: Status = 'blk: {
if no_orphans && (cfg!(any(target_os = "linux", target_os = "android")) || cfg!(target_os = "macos")) {
if no_orphans
&& (cfg!(any(target_os = "linux", target_os = "android"))
|| cfg!(target_os = "macos"))
{
let ppid = ParentDeathWatchdog::ppid_to_watch().unwrap_or(0);
#[cfg(target_os = "macos")]
let r: Option<Maybe<Status>> = wait_mac_kqueue(
Expand All @@ -3245,7 +3248,11 @@ mod spawn_process_body {
&mut out_fds_to_wait_for,
&mut out_fds,
);
#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "macos")))]
#[cfg(not(any(
target_os = "linux",
target_os = "android",
target_os = "macos"
)))]
let r: Option<Maybe<Status>> = {
let _ = ppid;
None
Expand Down
5 changes: 4 additions & 1 deletion src/spawn_sys/spawn_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,10 @@ pub fn spawn_process_posix(
let mut dup_stdout_to_stderr: bool = false;

// The label is only referenced from the Linux memfd fast-path below.
#[cfg_attr(not(any(target_os = "linux", target_os = "android")), allow(unused_labels))]
#[cfg_attr(
not(any(target_os = "linux", target_os = "android")),
allow(unused_labels)
)]
'stdio: for i in 0..3usize {
let fileno = Fd::from_native(FdT::try_from(i).unwrap());
let flag: u32 = (if i == 0 {
Expand Down
60 changes: 59 additions & 1 deletion test/js/bun/resolve/resolve.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { pathToFileURL } from "bun";
import { describe, expect, it } from "bun:test";
import { chmodSync, chownSync, mkdirSync, readFileSync, writeFileSync } from "fs";
import { chmodSync, chownSync, mkdirSync, readFileSync, symlinkSync, writeFileSync } from "fs";
import { bunEnv, bunExe, bunRun, isLinux, isWindows, joinP, tempDir, tempDirWithFiles } from "harness";
import { join, resolve, sep } from "path";

Expand Down Expand Up @@ -589,6 +589,64 @@ describe("wildcard exports with @ in matched subpath", () => {
});
});

// A package.json `imports` entry whose value is a bare package specifier
// (e.g. `"#res": "@myproject/resolver"`) is handed back to package-resolve
// for a second pass. Per the Node.js packages spec these are URL-like
// specifiers and must always use forward slashes. On Windows, the join that
// feeds the second pass was going through `platform::Auto` which normalizes
// `/` to `\`, turning `@myproject/resolver` into `@myproject\resolver` —
// the scoped-package match fails and Bun falls back to the legacy `main`
// field instead of `exports`. Linux/macOS aren't affected because `Auto`
// is already `Posix` there; this test is therefore Windows-only.
// https://github.com/oven-sh/bun/issues/30839
describe.if(isWindows)("#30839 - imports entry pointing at a scoped package", () => {
it("resolves via the target's exports, not its main", async () => {
using dir = tempDir("resolver-imports-scoped-pkg", {
"package.json": JSON.stringify({ name: "root", private: true, workspaces: ["packages/*"] }),
"packages/resolver/package.json": JSON.stringify({
name: "@myproject/resolver",
type: "module",
main: "./index.cjs",
exports: { ".": "./index.mjs" },
}),
"packages/resolver/index.mjs": "export const type = 'esm (from exports)';",
"packages/resolver/index.cjs": "module.exports = { type: 'cjs (from main)' };",
"packages/app/package.json": JSON.stringify({
name: "app",
type: "module",
dependencies: { "@myproject/resolver": "workspace:*" },
imports: { "#res": "@myproject/resolver" },
}),
"packages/app/test.mjs": `import { type } from "#res";\nconsole.log(type);`,
});
const root = String(dir);

// Wire up @myproject/resolver into app/node_modules so the second pass
// through the resolver (the one this fix repairs) can find it — without
// invoking `bun install`. `"junction"` is the Windows-appropriate symlink
// kind for directories.
mkdirSync(join(root, "packages/app/node_modules/@myproject"), { recursive: true });
symlinkSync(
join(root, "packages/resolver"),
join(root, "packages/app/node_modules/@myproject/resolver"),
"junction",
);

await using proc = Bun.spawn({
cmd: [bunExe(), "test.mjs"],
env: bunEnv,
cwd: join(root, "packages/app"),
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);

expect(stderr).toBe("");
expect(stdout).toBe("esm (from exports)\n");
expect(exitCode).toBe(0);
});
});

// dirInfoCachedMaybeLog reads the rfs.entries cache without checking the union
// tag. If readDirectory() previously failed with a non-ENOENT error (e.g.
// EACCES), a `.err` variant is stored there; re-resolving the directory after
Expand Down
Loading