sea: `--build-sea` produces a segfaulting executable on macOS x64 (v26.7.0), while the blob + postject path works on the same runtime
維護者通常 1 天內回覆
還沒有人認領這個 Issue。
評估
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 新手友好度
- 52/100
- Issue 類型
- 缺陷
- 描述清晰度
- 基本清楚
- 活躍度
- 活躍
- 技術堆疊
- javascript, node.js
研究方向
先使用文件記載的 node --build-sea 指令重現 macOS x64 上的失敗,接著將其 Mach-O 區段配置和 __init_offsets 與使用 --experimental-sea-config 加上 postject 的正常路徑進行比較。閱讀 #61504 所參照的現有 --build-sea 覆蓋;當產生的 SEA 可執行檔能在此主機上成功啟動,且不需要 postject fallback 時,即表示完成。
由索引模型根據 Issue 內容生成。
描述
Version
v26.7.0
Platform
Darwin 24.6.0 Darwin Kernel Version 24.6.0 x86_64
macOS 15.7.3 (24G419), Intel Core i5-7500
Subsystem
sea
What steps will reproduce the bug?
On macOS x64, an executable produced by node --build-sea segfaults on launch — including
for a one-line hello world. The same runtime, given the same script through
--experimental-sea-config + postject, produces an executable that runs.
$ echo 'console.log("hello");' > hello.js
# --build-sea
$ printf '{"main":"hello.js","output":"a-build-sea","disableExperimentalSEAWarning":true}' > a.json
$ node --build-sea a.json
Generated single executable .../bin/node + a.json -> a-build-sea
$ codesign --remove-signature a-build-sea && codesign --sign - a-build-sea
$ ./a-build-sea
Segmentation fault: 11 # exit 139
# the blob path, same node, same script
$ printf '{"main":"hello.js","output":"hello.blob","disableExperimentalSEAWarning":true}' > blob.json
$ node --experimental-sea-config blob.json
Wrote single executable preparation blob to hello.blob
$ cp "$(command -v node)" d-postject && chmod 755 d-postject
$ npx postject d-postject NODE_SEA_BLOB hello.blob \
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \
--macho-segment-name NODE_SEA --overwrite
$ codesign --remove-signature d-postject && codesign --sign - d-postject
$ ./d-postject
hello # exit 0
How often does it reproduce? Is there a required condition?
Every time, on this host. Not conditional on anything in the config:
| variant | result |
|---|---|
--build-sea, CommonJS (no mainFormat) |
SIGSEGV |
--build-sea, "mainFormat": "module" |
SIGSEGV |
--build-sea, no codesign step at all |
SIGSEGV |
--experimental-sea-config + postject, same node |
runs |
So it is neither the module format nor the ad-hoc signature.
What is the expected behavior? Why is that the expected behavior?
node --build-sea should produce a runnable executable — it is documented as the
single-command replacement for the blob + postject procedure, and the procedure it
replaces works on this exact runtime.
What do you see instead?
SIGSEGV before main, while dyld is running the binary's static initializers:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000001
thread #1, stop reason = EXC_BAD_ACCESS (code=1, address=0x1)
frame #0: 0x000000010000c8f0 a-build-sea`__cxx_global_var_init
dyld invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(...)
dyld mach_o::Header::forEachSection(...)
dyld dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const
dyld dyld4::JustInTimeLoader::runInitializers(dyld4::RuntimeState&) const
dyld dyld4::Loader::runInitializersBottomUp(...)
dyld dyld4::APIs::runAllInitializersForMain()
The faulting address is 0x1, which reads like an initializer entry that was not
relocated rather than a fault inside any particular initializer. (The frame #0 symbol
is a nearest-symbol guess and is probably not meaningful — the appended blob shifts
the symbolication.)
Additional information
Comparing the two outputs, the segment layout is structurally identical but
--build-sea places __DATA_CONST (and everything after it) one page higher than the
postject output does:
$ otool -l a-build-sea | grep -A4 LC_SEGMENT_64 | grep -E 'segname|vmaddr'
segname __TEXT
vmaddr 0x0000000100000000
segname __DATA_CONST
vmaddr 0x00000001061e1000
segname __DATA
vmaddr 0x0000000106394000
segname NODE_SEA
vmaddr 0x000000010640f000
segname __LINKEDIT
vmaddr 0x0000000106410000
$ otool -l d-postject | grep -A4 LC_SEGMENT_64 | grep -E 'segname|vmaddr'
segname __TEXT
vmaddr 0x0000000100000000
segname __DATA_CONST
vmaddr 0x00000001061e0000 # one page lower
segname __DATA
vmaddr 0x0000000106393000
segname NODE_SEA
vmaddr 0x000000010640e000
segname __LINKEDIT
vmaddr 0x000000010640f000
Both binaries carry __init_offsets and report identical Mach-O headers (ncmds 22,
sizeofcmds 2728), so the load commands themselves are not obviously malformed — but
__DATA_CONST moving without the initializer offsets following it would produce exactly
the observed 0x1. I have not confirmed that causally; it is where I would look first.
This is the same class of problem as #61483 (SEA build corrupting .gnu.hash on Linux
arm64) — the build step rewriting the container in a way the loader then rejects — on a
different platform and a different section. #61504 already skips --build-sea tests on
platforms where SEA is flaky; macOS x64 may belong in that set until this is understood.
Node was installed via nvm from the official tarball
(process.release.sourceUrl = https://nodejs.org/download/release/v26.7.0/node-v26.7.0.tar.gz),
so this is an official x64 build, not a self-compiled or Rosetta one.
Practical impact: a project shipping standalone executables cannot rely on --build-sea
on macOS x64 and has to keep the postject fallback alive, detecting the failure by
running the produced binary before trusting it.
- 主要語言
- JavaScript
- 星號
- 122k
- 分支
- 38.4k
- 平均合併
- 3 天 22 小時
- 30 天內合併 PR
- 273
環境準備
- 沒有 Dockerfile 或 Docker Compose 檔案
- 有 Pull Request 範本
- 閱讀貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
nodejs/node 的其他 Issue
-
node:internal/inspector/network_http: `TypeError: Missing dataLength` in event when response uses `setEncoding()`可能已有人在做 @lazerg 今天認領。 未關閉
難度 2/5 1-3 小時 新手友好度 78/100
維護者通常 1 天內回覆
-
build / doc: missing platform and toolchain info for `linux-x64-musl`可能已有人在做 @theSnackOverflow 於 1 天前認領。 未關閉alpine build doc
難度 2/5 1-3 小時 新手友好度 75/100
維護者通常 1 天內回覆
-
[Docs] `process.loadEnvFile()` does not document behaviour when variables already exist可能已有人在做 @Sepandard 於 10 天前認領。 未關閉doc
難度 1/5 1 小時以內 新手友好度 90/100
維護者通常 1 天內回覆
-
Stream.prototype.forEach will block in first promise in queue before read more chunk可能已有人在做 @mmustafasenoglu 於 11 天前認領。 未關閉doc
難度 2/5 1-3 小時 新手友好度 65/100
維護者通常 1 天內回覆
-
build
難度 1/5 1 小時以內 新手友好度 88/100
維護者通常 1 天內回覆
相似的 Issue
-
agentic-workflows
難度 1/5 1 小時以內 新手友好度 90/100
githubnext/gh-aw-cao#16599 ·
維護者通常 1 天內回覆
-
effort:low impact:medium status: auto-triaged UI / Studio
難度 2/5 1-3 小時 新手友好度 88/100
mastra-ai/mastra#26124 · 2 則留言 ·
維護者通常 1 天內回覆
-
allow igdb.com未關閉
難度 2/5 1-3 小時 新手友好度 61/100
AdguardTeam/HostlistsRegistry#939 ·
維護者通常 1 天內回覆
-
product / databases
難度 2/5 1-3 小時 新手友好度 82/100
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 68/100
smansfield635-create/smansfield635-create.github.io#5818 · 4 則留言 ·
維護者通常 1 天內回覆