Skip to content

localapp server start 在 Windows x64 上必定失败:native adapter --register 以 STATUS_HEAP_CORRUPTION (0xC0000374) 崩溃,daemon 永远不会被安装 #1

Description

@Patodo

环境

项目
平台 Windows 11(build 10.0.26200)x64
Node v24.21.0
npm 11.19.0
@patodo/localapp 0.2.1
native adapter runtime/native/win32-x64/localapp-native.exe,sha256 2c025476c800ebcece0a5cc158928c67a30b2b6529ccd1c3508a475f9fce12d1

概要

localapp server start 在 Windows 上必定失败:

{"error":{"code":"native_adapter_failed","message":"The LocalApp native adapter command failed"}}

之后 localapp server status 永远返回:

{"error":{"code":"daemon_unreachable","message":"The LocalApp daemon is unreachable"}}

根因是 localapp-native.exe --register --config <path>成功写完 localapp:// 注册表项之后,以 0xC0000374STATUS_HEAP_CORRUPTION)崩溃退出。CLI 仅依据退出码判定,于是把这条命令当成失败并中止流程,manager.install()(写 service/windows-user-task.json)根本没有执行,daemon 因此从未被安装。

复现步骤

npm install --global @patodo/localapp
localapp server start
# {"error":{"code":"native_adapter_failed","message":"The LocalApp native adapter command failed"}}

localapp server status
# {"error":{"code":"daemon_unreachable","message":"The LocalApp daemon is unreachable"}}

最小化复现(此时 %LOCALAPPDATA%\LocalApp\native-bridge.json 已由 CLI 写好):

$exe = "$env:LOCALAPPDATA\LocalApp\releases\<version>-<artifactDigest>\runtime\native\win32-x64\localapp-native.exe"
$cfg = "$env:LOCALAPPDATA\LocalApp\native-bridge.json"
$p = Start-Process -FilePath $exe -ArgumentList '--register','--config',$cfg -Wait -PassThru
$p.ExitCode   # -1073740940  (0xC0000374)

触发条件定位

决定是否崩溃的是 config 文件的位置(是否位于 LocalApp 支持目录内),而不是它的内容:

--config 指向 结果
%LOCALAPPDATA%\LocalApp\native-bridge.json(CLI 写的真实配置) 崩溃 -1073740940,3/3 稳定复现
%TEMP%\latest\minimal.json(内容相同,放在别处) 退出码 1,不崩溃
%LOCALAPPDATA%\LocalApp\test-bridge.json(同样的最小内容,放进支持目录) 崩溃 -1073740940
C:\nonexistent\nope.json 退出码 1,不崩溃
--register(不带 --config 退出码 1,不崩溃

其他子命令均正常:--permission-state--request-permission 都返回 granted 且退出码 0。

崩溃点在注册表写入之后:先删除 HKCU\Software\Classes\localapp,再执行 --register --config,该键会被正确重建(默认值指向 localapp-native.exe --scheme --config "..." "%1"),然后进程才崩溃。也就是说注册动作本身成功了,出问题的是成功路径之后的代码(很可能是退出前的清理/释放路径)。

崩溃证据

Windows 应用程序事件日志(事件 ID 1000,Provider Application Error):

出错应用程序名称: localapp-native.exe,版本: 0.0.0.0,时间戳: 0x6a86787e
出错模块名称: ntdll.dll,版本: 10.0.26100.9444,时间戳: 0x6bdf03ca
异常代码: 0xc0000374
错误偏移: 0x0000000000117eb5

0x117eb5 在多次运行中完全一致,是确定性崩溃。0xC0000374 为堆损坏,通常由堆元数据被越界写坏后、由 ntdll 在后续分配/释放时检出。

影响范围

  • localapp server start 在 Windows 上不可用。
  • daemon 从未安装:%LOCALAPPDATA%\LocalApp\service\windows-user-task.json 不存在,logs\run\ 为空目录。
  • 依赖本地 daemon 的后续流程全部无法进入:本地 Server、localapp login http://127.0.0.1:<port>localapp devapp install --target local

Server 本体没有问题。 直接启动 runtime 中的 server 可正常到达 ready:

$ node runtime/server/bin/server.mjs start --data-dir "C:\Users\p\AppData\Local\LocalApp\data" --host 127.0.0.1 --port 0
{"type":"starting","workerPid":17704}
Content storage: local filesystem (C:\Users\p\AppData\Local\LocalApp\data) — MinIO unavailable
{"type":"ready","listenUrl":"http://127.0.0.1:53111","url":"http://127.0.0.1:53111","workerPid":17704,"setupUrl":"http://127.0.0.1:53111/setup?token=..."}

所以问题被完全隔离在 win32 native adapter 的 --register 路径上。

附带发现:localapp server run 在 Windows 上也无法按文档直接使用

README 把 localapp server run 描述为“以前台模式运行同一 Server,适合容器和服务管理器”。在 Windows 上不带额外环境变量执行它必定失败:

$ localapp server run
{"error":{"code":"command_failed","message":"LocalApp command failed"}}

原因在 bundle 内的 bin/localapp.mjs:29722spawnOwnedProcess() 在 win32 上要求能构造 Job Object adapter:

const windowsAdapter = options2.windowsAdapter ?? createWindowsProcessTreeAdapterFromEnvironment();
if (windowsAdapter === void 0) {
  throw new Error("Windows process-tree adapter is unavailable; refusing to spawn without atomic Job Object ownership");
}

windowsNativeExecutableFromEnvironment() 只从 process.env.LOCALAPP_RELEASE_PATH 推导 exe 路径,该变量仅由 runtime/bootstrap/localapp-daemon-bootstrap.mjs 设置。用户在 shell 里按 README 直接运行 localapp server run 时它必然为空,于是抛出的是普通 Error 而非 LocalAppLifecycleError,绕过结构化错误分支,被顶层 catch-all 归为 command_failed,丢失了真实原因。

显式设置该变量后即可正常前台启动(已用 release 目录验证):

$ LOCALAPP_RELEASE_PATH="C:\...\releases\0.2.1-<digest>" localapp server run
{"type":"starting","workerPid":23260}
{"type":"ready","listenUrl":"http://127.0.0.1:64586", ...}

若“必须经由 daemon bootstrap 调用”是有意设计,建议 server run 至少返回可读的错误码(例如 native_adapter_unsupported/单独的错误码,而不是 command_failed),并在 README 中说明该前置条件。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions