Skip to content

[DimAgent][Bug]: Light OCR 安装校验必然失败(smoke 重定向 USERPROFILE → NVIDIA DXCache 为空 → ORT WebGPU 栈溢出) #19

Description

@baoyu0

环境

DimAgent 桌面端 0.9.33 (0.9.33.0)
内置 CLI (resources/runtime/cli/dim.exe) dimcode 0.5.6 (Bun 1.3.8 standalone)
Light OCR 组件 0.5.7-ppocrv6-small-native-20260719.1.desktop.1 (win32-x64)
载荷 SHA-256 e3f3a14cfda8e2e9a27679d0ffc9e3096ada9102882c5ab9a6c9032a17fefcb9
系统 Windows 11 专业版 26200 (10.0.26200) x64
CPU / 内存 Intel Core i7-14700F / 32 GB
GPU / 驱动 NVIDIA GeForce RTX 5060 Ti / 32.0.16.1692 (2026-09-04)

现象

设置 → 功能 里的 Light OCR 一直显示「失败」,无法安装/启用。失败信息为:

FEATURE_VERIFY_FAILED: light-ocr: Command failed:
C:\...\DimAgent\resources\runtime\cli\dim.exe ocr recognize
  C:\...\feature-runtime-fixtures\known-text.png
  --provider light-ocr-local --model ppocrv6-small
  --out-dir C:\Users\...\Temp\dimcode-feature-smoke-bVs0sP\known-text.png --json

============================================================
Bun v1.3.8 (b64edcb4) Windows x64
Features: Bun.stderr(2) Bun.stdin(2) Bun.stdout(2) jsc standalone_executable process_dlopen(2)
Elapsed: 34190ms | User: 3765ms | Sys: 28156ms
RSS: 0.74GB | Peak: 0.74GB | Commit: 1.04GB | Faults: 254646 | Machine: 34.05GB

panic(thread 32628): Stack overflow
oh no: Bun has crashed. This indicates a bug in Bun, not your code.
 https://bun.report/1.3.8/w_1b64edcbkgEugggCCcKERNELBASE.dlluttHCoBNvMemMapStoragex.dll46kuBCoBNvMemMapStoragex.dll6ppw...gg6SA7

panic: Segmentation fault at address 0x1CDB000000
panicked during a panic. Aborting.

在界面上点重试也永远不会成功(下节说明原因)。

关键结论:OCR 引擎本身是好的,崩的是 smoke 自检

用同一个 dim.exe、同一个官方载荷,只要给一个正常的用户 profile,两个 fixture 全部通过:

known-text.png   ok=true  pageCount=1  2534–5602 ms   text="DIMCODE OCR 12345678"
mixed.pdf        ok=true  pageCount=2  2716–3158 ms   text="MIXED PAGE 1 DIMCODE OCR SCANNED PAGE 987654"

也就是说 light_ocr_node.node + onnxruntime WebGPU 在这台机器上工作正常,问题只出在校验时的环境构造

根因

FeatureRuntimeManager.smoke(app.asar → packages/electron-main)为了隔离,会把 OCR 自检跑在一个全新临时 profile 下:

const smokeDir = await realpath(await mkdtemp(join(tmpdir(), "dimcode-feature-smoke-")));
const fakeHome = join(smokeDir, "home");
const env = {
  ...this.options.env(),
  HOME: fakeHome,
  USERPROFILE: fakeHome,
  XDG_CONFIG_HOME: join(fakeHome, "config"),
  XDG_CACHE_HOME: join(fakeHome, "cache"),
  DIMCODE_HOME: join(fakeHome, "dimcode"),
  DOTNET_CLI_HOME: fakeHome,
  OFFICECLI_NO_AUTO_RESIDENT: "1",
  DIMCODE_LIGHT_OCR_RUNTIME_ROOT: installRoot,
};
// dim.exe ocr recognize ...  (timeout 180s)

问题在于:NVIDIA 驱动的 DirectX 着色器缓存路径跟着 USERPROFILE,而不是 %LOCALAPPDATA% 环境变量。
重定向 USERPROFILE 之后,驱动把 DXCache 建在临时目录里:

<TEMP>\dimcode-feature-smoke-XXXX\home\
  appdata\local\NVIDIA\DXCache\           <-- 空的
  appdata\locallow\NVIDIA\DXCache\        <-- 空的

于是 onnxruntime 的 WebGPU execution provider 必须从零开始做 DXC 着色器编译,在这台机器的驱动上会在 NvMemMapStoragex.dllnvhdcsi.inf 组件)里递归到线程栈溢出,进程以 0xC0000005 终止,Bun 打印上面的 panic。

这解释了两个反常指标:

  • Sys: 28156ms / User: 3765ms —— 34 秒里 28 秒是内核态,几乎全耗在驱动/页错误上(Faults: 254646);
  • 崩溃栈帧在 KERNELBASE.dllNvMemMapStoragex.dll 之间反复出现 —— 典型的驱动内深递归。

因为 mkdtemp 每次都生成新的随机目录、结束后还 rm -rf着色器缓存每次都是冷的,所以重试不会变好,只会重复崩溃。

复现与定位实验(本机实测)

场景 结果
App 自检(重定向 profile,冷 DXCache) 崩溃:34190 / 50007 / 51793 / 83471 ms,栈帧与上报一致
重定向 profile + 把 %LOCALAPPDATA%\NVIDIA\DXCache 预拷进 fake home(仅此一项,脚本见下节对照组) 通过,2788 ms
真实 profile(DXCache 已预热) 通过,2534–5602 ms

第三行证明:唯一变量就是那张空的 DXCache。(上面两行都是用下一节的脚本实跑的结果。)

顺带一个有用的事实:崩溃并不是彻底的死局。同一次 smoke 里,第 1 个 fixture 崩溃后(那次已经往缓存里写了条目),第 2 个 fixture(mixed.pdf在同一个 fake home 下直接通过。也就是崩溃后的「第二次」是能成功的。

最小复现

不需要装 DimAgent,只要有 dim.exe 和一份 light-ocr 运行时就够了:

$cli      = "$env:LOCALAPPDATA\Programs\DimAgent\resources\runtime\cli\dim.exe"
$fixtures = "$env:LOCALAPPDATA\Programs\DimAgent\resources\feature-runtime-fixtures"
# light-ocr 载荷解包后的根目录(含 manifest.json / engine / model)
$ocrRoot  = "<path-to>\light-ocr"

$smoke = Join-Path $env:TEMP ("dim-ocr-repro-" + [guid]::NewGuid().ToString("N").Substring(0,6))
$fakeHome = Join-Path $smoke "home"
New-Item -ItemType Directory -Force -Path $fakeHome | Out-Null

# 等价于 FeatureRuntimeManager.smoke 的环境
[Environment]::SetEnvironmentVariable("HOME",            $fakeHome, "Process")
[Environment]::SetEnvironmentVariable("USERPROFILE",     $fakeHome, "Process")
[Environment]::SetEnvironmentVariable("XDG_CONFIG_HOME", (Join-Path $fakeHome "config"), "Process")
[Environment]::SetEnvironmentVariable("XDG_CACHE_HOME",  (Join-Path $fakeHome "cache"),  "Process")
[Environment]::SetEnvironmentVariable("DIMCODE_HOME",    (Join-Path $fakeHome "dimcode"),"Process")
[Environment]::SetEnvironmentVariable("DIMCODE_LIGHT_OCR_RUNTIME_ROOT", $ocrRoot, "Process")

& $cli ocr recognize (Join-Path $fixtures "known-text.png") `
      --provider light-ocr-local --model ppocrv6-small `
      --out-dir (Join-Path $smoke "known-text.png") --json
# => panic: Stack overflow / Segmentation fault

# 对照组:先把 DXCache 拷进 fake home,再跑一次
$dst = Join-Path $fakeHome "appdata\local\NVIDIA\DXCache"
New-Item -ItemType Directory -Force -Path $dst | Out-Null
Copy-Item "$env:LOCALAPPDATA\NVIDIA\DXCache\*" $dst -Force
& $cli ocr recognize (Join-Path $fixtures "known-text.png") `
      --provider light-ocr-local --model ppocrv6-small `
      --out-dir (Join-Path $smoke "known-text.png") --json
# => {"ok":true,...,"text":"DIMCODE OCR\n12345678"}   ~2.5s

建议的修法

按代价从低到高:

  1. 崩溃后自动重试一次。实测崩溃那次已经把部分着色器写进缓存,紧接的第二次就能通过(同一次 smoke 的 mixed.pdf 即为例证)。这是最小改动,也能顺带覆盖第一种真实用户场景。
  2. OCR 自检不要重定向 USERPROFILE。只隔离 DIMCODE_HOME / XDG_* 就足够达到「不污染用户配置」的目的;或者把 LOCALAPPDATA(以及驱动实际使用的 <USERPROFILE>\AppData\Local)显式指向真实路径,让驱动复用已预热的 DXCache。
  3. 让自检走 CPU execution providerruntime-descriptor.jsonautoPolicy 目前是 ["webgpu","cpu"];如果校验用 CPU、正常运行仍用 WebGPU,就完全不会碰 DXC 编译,也就不会触发这个驱动崩溃。这样还能顺便把校验时间从几十秒降到几秒。
  4. 如果希望保留 WebGPU 自检,可在跑之前做一次热机(先编译一次再判定),避免把「冷缓存首次编译」当成失败。

补充:这个崩溃不限于自检路径。任何让 USERPROFILE\AppData\Local\NVIDIA\DXCache 变空的场景(换驱动、清理工具、全新用户)都可能让用户第一次真正使用本地 OCR 时同样崩掉;所以第 2/3 条对正常使用路径也有价值。

我这边的临时规避

作为用户侧临时手段,我把官方载荷(SHA-256 与 feature-runtime-catalog.json 一致、light_ocr_node.node 签名有效)直接装到 App 期望的目录并写入校验记录:

%APPDATA%\DimAgent\feature-runtimes\light-ocr\0.5.7-ppocrv6-small-native-20260719.1.desktop.1\win32-x64\
%APPDATA%\DimAgent\feature-runtimes\light-ocr\0.5.7-ppocrv6-small-native-20260719.1.desktop.1\win32-x64.json

App 启动时 applyManagedInstallation 只做 validateRecord + validatePayload(不跑 smoke),因此能被采纳、功能变可用。
但这显然只是绕过,只要用户点一次「重试/安装」就会再次回滚。希望官方从上面 1–4 里挑一个修掉。

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions