mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
### What does this PR do? Closes #13012 On Linux, when any Bun process spawned by `runner.node.mjs` crashes, we run GDB in batch mode to print a backtrace from the core file. And on all platforms, we run a mini `bun.report` server which collects crashes reported by any Bun process executed during the tests, and after each test `runner.node.mjs` fetches and prints any new crashes from the server. <details> <summary>example 1</summary> ``` #0 crash_handler.crash () at crash_handler.zig:1513 #1 0x0000000002cf4020 in crash_handler.crashHandler (reason=..., error_return_trace=0x0, begin_addr=...) at crash_handler.zig:479 #2 0x0000000002cefe25 in crash_handler.handleSegfaultPosix (sig=<optimized out>, info=<optimized out>) at crash_handler.zig:800 #3 0x00000000045a1124 in WTF::jscSignalHandler (sig=11, info=0x7ffe044e30b0, ucontext=0x0) at vendor/WebKit/Source/WTF/wtf/threads/Signals.cpp:548 #4 <signal handler called> #5 JSC::JSCell::type (this=0x0) at vendor/WebKit/Source/JavaScriptCore/runtime/JSCellInlines.h:137 #6 JSC::JSObject::getOwnNonIndexPropertySlot (this=0x150bc914fe18, vm=..., structure=0x150a0102de50, propertyName=..., slot=...) at vendor/WebKit/Source/JavaScriptCore/runtime/JSObject.h:1348 #7 JSC::JSObject::getPropertySlot<false> (this=0x150bc914fe18, globalObject=0x150b864e0088, propertyName=..., slot=...) at vendor/WebKit/Source/JavaScriptCore/runtime/JSObject.h:1433 #8 JSC::JSValue::getPropertySlot (this=0x7ffe044e4880, globalObject=0x150b864e0088, propertyName=..., slot=...) at vendor/WebKit/Source/JavaScriptCore/runtime/JSCJSValueInlines.h:1108 #9 JSC::JSValue::get (this=0x7ffe044e4880, globalObject=0x150b864e0088, propertyName=..., slot=...) at vendor/WebKit/Source/JavaScriptCore/runtime/JSCJSValueInlines.h:1065 #10 JSC::LLInt::performLLIntGetByID (bytecodeIndex=..., codeBlock=0x150b861e7740, globalObject=0x150b864e0088, baseValue=..., ident=..., metadata=...) at vendor/WebKit/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp:878 #11 0x0000000004d7b055 in llint_slow_path_get_by_id (callFrame=0x7ffe044e4ab0, pc=0x150bc92ea0e7) at vendor/WebKit/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp:946 #12 0x0000000003dd6042 in llint_op_get_by_id () #13 0x0000000000000000 in ?? () ``` </details> <details> <summary>example 2</summary> ``` #0 crash_handler.crash () at crash_handler.zig:1513 #1 0x0000000002c5db80 in crash_handler.crashHandler (reason=..., error_return_trace=0x0, begin_addr=...) at crash_handler.zig:479 #2 0x0000000002c59f60 in crash_handler.handleSegfaultPosix (sig=<optimized out>, info=<optimized out>) at crash_handler.zig:800 #3 0x00000000042ecc88 in WTF::jscSignalHandler (sig=11, info=0xfffff60141b0, ucontext=0xfffff6014230) at vendor/WebKit/Source/WTF/wtf/threads/Signals.cpp:548 #4 <signal handler called> #5 bun.js.api.FFIObject.Reader.u8 (globalObject=0x4000554e0088) at /var/lib/buildkite-agent/builds/ip-172-31-75-92/bun/bun/src/bun.js/api/FFIObject.zig:65 #6 bun.js.jsc.host_fn.toJSHostCall__anon_1711576 (globalThis=0x4000554e0088, args=...) at /var/lib/buildkite-agent/builds/ip-172-31-75-92/bun/bun/src/bun.js/jsc/host_fn.zig:97 #7 bun.js.jsc.host_fn.DOMCall("Reader"[0..6],bun.js.api.FFIObject.Reader,"u8"[0..2],.{ .reads = .{ ... }, .writes = .{ ... } }).slowpath (globalObject=0x4000554e0088, thisValue=70370172175040, arguments_ptr=0xfffff6015460, arguments_len=1) at /var/lib/buildkite-agent/builds/ip-172-31-75-92/bun/bun/src/bun.js/jsc/host_fn.zig:490 #8 0x000040003419003c in ?? () #9 0x0000400055173440 in ?? () ``` </details> I used GDB instead of LLDB (as the branch name suggests) because it seems to produce more useful stack traces with musl libc. - [x] on linux, use gdb to print from core dump of main bun process crashed - [x] on linux, use gdb to print from all new core dumps (so including bun subprocesses spawned by the test that crashed) - [x] on all platforms, use a mini bun.report server to print a self-reported trace (depends on oven-sh/bun.report#15; for now our package.json points to a commit on the branch of that repo) - [x] fix trying to fetch stack traces too early on windows - [x] use output groups so the traces show up alongside the log for the specific test instead of having to find it in the logs from the entire run - [x] get oven-sh/bun.report#15 merged, and point to a bun.report commit on the main branch instead of the PR branch in package.json ### How did you verify your code works? Manually, and in CI with a crashing test. --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
425 lines
11 KiB
PowerShell
Executable File
425 lines
11 KiB
PowerShell
Executable File
# Version: 11
|
|
# A script that installs the dependencies needed to build and test Bun.
|
|
# This should work on Windows 10 or newer with PowerShell.
|
|
|
|
# If this script does not work on your machine, please open an issue:
|
|
# https://github.com/oven-sh/bun/issues
|
|
|
|
# If you need to make a change to this script, such as upgrading a dependency,
|
|
# increment the version comment to indicate that a new image should be built.
|
|
# Otherwise, the existing image will be retroactively updated.
|
|
|
|
param (
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$CI = $false,
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$Optimize = $CI
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
|
|
|
|
function Execute-Command {
|
|
$command = $args -join ' '
|
|
Write-Output "$ $command"
|
|
|
|
& $args[0] $args[1..$args.Length]
|
|
|
|
if ((-not $?) -or ($LASTEXITCODE -ne 0 -and $null -ne $LASTEXITCODE)) {
|
|
throw "Command failed: $command"
|
|
}
|
|
}
|
|
|
|
function Which {
|
|
param ([switch]$Required = $false)
|
|
|
|
foreach ($command in $args) {
|
|
$result = Get-Command $command -ErrorAction SilentlyContinue
|
|
if ($result -and $result.Path) {
|
|
return $result.Path
|
|
}
|
|
}
|
|
|
|
if ($Required) {
|
|
$commands = $args -join ', '
|
|
throw "Command not found: $commands"
|
|
}
|
|
}
|
|
|
|
function Execute-Script {
|
|
param (
|
|
[Parameter(Mandatory = $true, Position = 0)]
|
|
[string]$Path
|
|
)
|
|
|
|
$pwsh = Which pwsh powershell -Required
|
|
Execute-Command $pwsh $Path
|
|
}
|
|
|
|
function Download-File {
|
|
param (
|
|
[Parameter(Mandatory = $true, Position = 0)]
|
|
[string]$Url,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$Name,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$Path
|
|
)
|
|
|
|
if (-not $Name) {
|
|
$Name = [System.IO.Path]::ChangeExtension([System.IO.Path]::GetRandomFileName(), [System.IO.Path]::GetExtension($Url))
|
|
}
|
|
|
|
if (-not $Path) {
|
|
$Path = "$env:TEMP\$Name"
|
|
}
|
|
|
|
$client = New-Object System.Net.WebClient
|
|
for ($i = 0; $i -lt 10 -and -not (Test-Path $Path); $i++) {
|
|
try {
|
|
$client.DownloadFile($Url, $Path)
|
|
} catch {
|
|
Write-Warning "Failed to download $Url, retry $i..."
|
|
Start-Sleep -s $i
|
|
}
|
|
}
|
|
|
|
return $Path
|
|
}
|
|
|
|
function Install-Chocolatey {
|
|
if (Which choco) {
|
|
return
|
|
}
|
|
|
|
Write-Output "Installing Chocolatey..."
|
|
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
|
|
$installScript = Download-File "https://community.chocolatey.org/install.ps1"
|
|
Execute-Script $installScript
|
|
Refresh-Path
|
|
}
|
|
|
|
function Refresh-Path {
|
|
$paths = @(
|
|
[System.Environment]::GetEnvironmentVariable("Path", "Machine"),
|
|
[System.Environment]::GetEnvironmentVariable("Path", "User"),
|
|
[System.Environment]::GetEnvironmentVariable("Path", "Process")
|
|
)
|
|
$uniquePaths = $paths |
|
|
Where-Object { $_ } |
|
|
ForEach-Object { $_.Split(';', [StringSplitOptions]::RemoveEmptyEntries) } |
|
|
Where-Object { $_ -and (Test-Path $_) } |
|
|
Select-Object -Unique
|
|
$env:Path = ($uniquePaths -join ';').TrimEnd(';')
|
|
|
|
if ($env:ChocolateyInstall) {
|
|
Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
function Add-To-Path {
|
|
$absolutePath = Resolve-Path $args[0]
|
|
$currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
|
|
if ($currentPath -like "*$absolutePath*") {
|
|
return
|
|
}
|
|
|
|
$newPath = $currentPath.TrimEnd(";") + ";" + $absolutePath
|
|
if ($newPath.Length -ge 2048) {
|
|
Write-Warning "PATH is too long, removing duplicate and old entries..."
|
|
|
|
$paths = $currentPath.Split(';', [StringSplitOptions]::RemoveEmptyEntries) |
|
|
Where-Object { $_ -and (Test-Path $_) } |
|
|
Select-Object -Unique
|
|
|
|
$paths += $absolutePath
|
|
$newPath = $paths -join ';'
|
|
while ($newPath.Length -ge 2048 -and $paths.Count -gt 1) {
|
|
$paths = $paths[1..$paths.Count]
|
|
$newPath = $paths -join ';'
|
|
}
|
|
}
|
|
|
|
Write-Output "Adding $absolutePath to PATH..."
|
|
[Environment]::SetEnvironmentVariable("Path", "$newPath", "Machine")
|
|
Refresh-Path
|
|
}
|
|
|
|
function Set-Env {
|
|
param (
|
|
[Parameter(Mandatory = $true, Position = 0)]
|
|
[string]$Name,
|
|
[Parameter(Mandatory = $true, Position = 1)]
|
|
[string]$Value
|
|
)
|
|
|
|
Write-Output "Setting environment variable $Name=$Value..."
|
|
[System.Environment]::SetEnvironmentVariable("$Name", "$Value", "Machine")
|
|
[System.Environment]::SetEnvironmentVariable("$Name", "$Value", "Process")
|
|
}
|
|
|
|
function Install-Package {
|
|
param (
|
|
[Parameter(Mandatory = $true, Position = 0)]
|
|
[string]$Name,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$Command = $Name,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$Version,
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$Force = $false,
|
|
[Parameter(Mandatory = $false)]
|
|
[string[]]$ExtraArgs = @()
|
|
)
|
|
|
|
if (-not $Force `
|
|
-and (Which $Command) `
|
|
-and (-not $Version -or (& $Command --version) -like "*$Version*")) {
|
|
return
|
|
}
|
|
|
|
Write-Output "Installing $Name..."
|
|
$flags = @(
|
|
"--yes",
|
|
"--accept-license",
|
|
"--no-progress",
|
|
"--force"
|
|
)
|
|
if ($Version) {
|
|
$flags += "--version=$Version"
|
|
}
|
|
|
|
Execute-Command choco install $Name @flags @ExtraArgs
|
|
Refresh-Path
|
|
}
|
|
|
|
function Install-Packages {
|
|
foreach ($package in $args) {
|
|
Install-Package $package
|
|
}
|
|
}
|
|
|
|
function Install-Common-Software {
|
|
Install-Chocolatey
|
|
Install-Pwsh
|
|
Install-Git
|
|
Install-Packages curl 7zip nssm
|
|
Install-NodeJs
|
|
Install-Bun
|
|
Install-Cygwin
|
|
if ($CI) {
|
|
# FIXME: Installing tailscale causes the AWS metadata server to become unreachable
|
|
# Install-Tailscale
|
|
Install-Buildkite
|
|
}
|
|
}
|
|
|
|
function Install-Pwsh {
|
|
Install-Package powershell-core -Command pwsh
|
|
|
|
if ($CI) {
|
|
$shellPath = (Which pwsh -Required)
|
|
New-ItemProperty `
|
|
-Path "HKLM:\\SOFTWARE\\OpenSSH" `
|
|
-Name DefaultShell `
|
|
-Value $shellPath `
|
|
-PropertyType String `
|
|
-Force
|
|
}
|
|
}
|
|
|
|
function Install-Git {
|
|
Install-Packages git
|
|
|
|
if ($CI) {
|
|
Execute-Command git config --system --add safe.directory "*"
|
|
Execute-Command git config --system core.autocrlf false
|
|
Execute-Command git config --system core.eol lf
|
|
Execute-Command git config --system core.longpaths true
|
|
}
|
|
}
|
|
|
|
function Install-NodeJs {
|
|
Install-Package nodejs -Command node -Version "24.3.0"
|
|
}
|
|
|
|
function Install-Bun {
|
|
Install-Package bun -Version "1.2.17"
|
|
}
|
|
|
|
function Install-Cygwin {
|
|
Install-Package cygwin
|
|
Add-To-Path "C:\tools\cygwin\bin"
|
|
}
|
|
|
|
function Install-Tailscale {
|
|
Install-Package tailscale
|
|
}
|
|
|
|
function Install-Buildkite {
|
|
if (Which buildkite-agent) {
|
|
return
|
|
}
|
|
|
|
Write-Output "Installing Buildkite agent..."
|
|
$env:buildkiteAgentToken = "xxx"
|
|
$installScript = Download-File "https://raw.githubusercontent.com/buildkite/agent/main/install.ps1"
|
|
Execute-Script $installScript
|
|
Refresh-Path
|
|
}
|
|
|
|
function Install-Build-Essentials {
|
|
Install-Visual-Studio
|
|
Install-Packages `
|
|
cmake `
|
|
make `
|
|
ninja `
|
|
ccache `
|
|
python `
|
|
golang `
|
|
nasm `
|
|
ruby `
|
|
strawberryperl `
|
|
mingw
|
|
Install-Rust
|
|
# Needed to remap stack traces
|
|
Install-PdbAddr2line
|
|
Install-Llvm
|
|
}
|
|
|
|
function Install-Visual-Studio {
|
|
param (
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$Edition = "community"
|
|
)
|
|
|
|
Write-Output "Downloading Visual Studio installer..."
|
|
$vsInstaller = Download-File "https://aka.ms/vs/17/release/vs_$Edition.exe"
|
|
|
|
Write-Output "Installing Visual Studio..."
|
|
$vsInstallArgs = @(
|
|
"--passive",
|
|
"--norestart",
|
|
"--wait",
|
|
"--force",
|
|
"--locale en-US",
|
|
"--add Microsoft.VisualStudio.Workload.NativeDesktop",
|
|
"--includeRecommended"
|
|
)
|
|
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
|
|
$startInfo.FileName = $vsInstaller
|
|
$startInfo.Arguments = $vsInstallArgs -join ' '
|
|
$startInfo.CreateNoWindow = $true
|
|
$process = New-Object System.Diagnostics.Process
|
|
$process.StartInfo = $startInfo
|
|
$process.Start()
|
|
$process.WaitForExit()
|
|
if ($process.ExitCode -ne 0) {
|
|
throw "Failed to install Visual Studio: code $($process.ExitCode)"
|
|
}
|
|
}
|
|
|
|
function Install-Rust {
|
|
if (Which rustc) {
|
|
return
|
|
}
|
|
|
|
Write-Output "Installing Rustup..."
|
|
$rustupInit = Download-File "https://win.rustup.rs/" -Name "rustup-init.exe"
|
|
|
|
Write-Output "Installing Rust..."
|
|
Execute-Command $rustupInit -y
|
|
|
|
Write-Output "Moving Rust to $env:ProgramFiles..."
|
|
$rustPath = Join-Path $env:ProgramFiles "Rust"
|
|
if (-not (Test-Path $rustPath)) {
|
|
New-Item -Path $rustPath -ItemType Directory
|
|
}
|
|
Move-Item "$env:UserProfile\.cargo" "$rustPath\cargo" -Force
|
|
Move-Item "$env:UserProfile\.rustup" "$rustPath\rustup" -Force
|
|
|
|
Write-Output "Setting environment variables for Rust..."
|
|
Set-Env "CARGO_HOME" "$rustPath\cargo"
|
|
Set-Env "RUSTUP_HOME" "$rustPath\rustup"
|
|
Add-To-Path "$rustPath\cargo\bin"
|
|
}
|
|
|
|
function Install-PdbAddr2line {
|
|
Execute-Command cargo install --examples "pdb-addr2line@0.11.2"
|
|
}
|
|
|
|
function Install-Llvm {
|
|
Install-Package llvm `
|
|
-Command clang-cl `
|
|
-Version "19.1.7"
|
|
Add-To-Path "$env:ProgramFiles\LLVM\bin"
|
|
}
|
|
|
|
function Optimize-System {
|
|
Disable-Windows-Defender
|
|
Disable-Windows-Threat-Protection
|
|
Disable-Windows-Services
|
|
Disable-Power-Management
|
|
}
|
|
|
|
function Optimize-System-Needs-Reboot {
|
|
Uninstall-Windows-Defender
|
|
}
|
|
|
|
function Disable-Windows-Defender {
|
|
Write-Output "Disabling Windows Defender..."
|
|
Set-MpPreference -DisableRealtimeMonitoring $true
|
|
Add-MpPreference -ExclusionPath "C:\", "D:\"
|
|
}
|
|
|
|
function Disable-Windows-Threat-Protection {
|
|
$itemPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows Advanced Threat Protection"
|
|
if (Test-Path $itemPath) {
|
|
Write-Output "Disabling Windows Threat Protection..."
|
|
Set-ItemProperty -Path $itemPath -Name "ForceDefenderPassiveMode" -Value 1 -Type DWORD
|
|
}
|
|
}
|
|
|
|
function Uninstall-Windows-Defender {
|
|
Write-Output "Uninstalling Windows Defender..."
|
|
Uninstall-WindowsFeature -Name Windows-Defender
|
|
}
|
|
|
|
function Disable-Windows-Services {
|
|
$services = @(
|
|
"WSearch", # Windows Search
|
|
"wuauserv", # Windows Update
|
|
"DiagTrack", # Connected User Experiences and Telemetry
|
|
"dmwappushservice", # WAP Push Message Routing Service
|
|
"PcaSvc", # Program Compatibility Assistant
|
|
"SysMain" # Superfetch
|
|
)
|
|
|
|
foreach ($service in $services) {
|
|
Stop-Service $service -Force
|
|
Set-Service $service -StartupType Disabled
|
|
}
|
|
}
|
|
|
|
function Disable-Power-Management {
|
|
Write-Output "Disabling Power Management..."
|
|
powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c # High performance
|
|
powercfg /change monitor-timeout-ac 0
|
|
powercfg /change monitor-timeout-dc 0
|
|
powercfg /change standby-timeout-ac 0
|
|
powercfg /change standby-timeout-dc 0
|
|
powercfg /change hibernate-timeout-ac 0
|
|
powercfg /change hibernate-timeout-dc 0
|
|
}
|
|
|
|
if ($Optimize) {
|
|
Optimize-System
|
|
}
|
|
|
|
Install-Common-Software
|
|
Install-Build-Essentials
|
|
|
|
if ($Optimize) {
|
|
Optimize-System-Needs-Reboot
|
|
}
|