Skip to content

fix(cli): guard systeminformation.cpu() against uncatchable os.cpus()… - #1377

Open
heavymio wants to merge 1 commit into
CodebuffAI:mainfrom
heavymio:patch-2
Open

heavymio wants to merge 1 commit into
CodebuffAI:mainfrom
heavymio:patch-2

Conversation

@heavymio

@heavymio heavymio commented Sep 17, 2026

Copy link
Copy Markdown

… throw on ARM Linux (hotplug skew) — see #1374

Patch refined and tested

The patch in commit 1333802 is close, but the cpus() pre-check needs a fix: on Bun's ARM Linux runtime with CPU hotplug skew, os.cpus() can throw synchronously, so calling cpus() without a try/catch can crash before we ever reach the guarded si.cpu().

Updated patch:

  • cpus() wrapped in try/catch — if it throws, return empty values + logger.warn immediately.
  • systeminformation.cpu() in try/catch — catches the uncaught exception from the nextTick callback inside lib/cpu.js:956.
  • Promise.all now uses getCpuInfoSafe() (removed the duplicate systeminformationModule.cpu() call).
  • Fallback logging via the existing logger (fingerprintType: cpu_pre_check_failed / cpu_info_failed).

Diagnosis confirmed via the mount-namespace workaround:

  • frozen CPU snapshot (8 CPUs consistent across /proc/stat, /proc/cpuinfo, /sys/devices/system/cpu/online) → CLI stays up.
  • live skewed state (9/8/9) → crash ~3s after start.

Fallback behavior: fingerprint still generates (empty CPU fields or legacy path); process is stable, not ideal for fingerprinting uniqueness but no longer crashes.

Closes #1374

… throw on ARM Linux (hotplug skew) — see CodebuffAI#1374

### Patch refined and tested

The patch in commit `1333802` is close, but the `cpus()` pre-check needs a fix: on Bun's ARM Linux runtime with CPU hotplug skew, `os.cpus()` can throw synchronously, so calling `cpus()` without a `try/catch` can crash before we ever reach the guarded `si.cpu()`.

Updated patch:
- `cpus()` wrapped in `try/catch` — if it throws, return empty values + `logger.warn` immediately.
- `systeminformation.cpu()` in `try/catch` — catches the uncaught exception from the `nextTick` callback inside `lib/cpu.js:956`.
- `Promise.all` now uses `getCpuInfoSafe()` (removed the duplicate `systeminformationModule.cpu()` call).
- Fallback logging via the existing `logger` (`fingerprintType: cpu_pre_check_failed` / `cpu_info_failed`).

Diagnosis confirmed via the mount-namespace workaround:
- frozen CPU snapshot (8 CPUs consistent across /proc/stat, /proc/cpuinfo, /sys/devices/system/cpu/online) → CLI stays up.
- live skewed state (9/8/9) → crash ~3s after start.

Fallback behavior: fingerprint still generates (empty CPU fields or legacy path); process is stable, not ideal for fingerprinting uniqueness but no longer crashes.
@codebuff-team

Copy link
Copy Markdown
Contributor

Thanks for digging into #1374 - the instinct to guard fingerprinting so it can't take down the CLI is correct, and the cpus() pre-check plus structured logger.warn reporting is a reasonable pattern to follow in this file.

Two things concern me before this is portable:

  1. The core claim contradicts the fix. You state the crash comes from an exception thrown inside a nextTick callback deep in systeminformation's lib/cpu.js:956 - i.e. it's the classic "async callback throws after the call stack that invoked it has already returned" problem. A try/catch wrapped around await systeminformationModule.cpu() only catches synchronous throws or promise rejections. If the underlying library really does throw from a detached nextTick callback without going through the promise chain, it becomes an uncaughtException/unhandledRejection on the process, and your try/catch here won't see it at all. If that's really the mechanism, the fix needs a process.on('uncaughtException', ...) handler (scoped carefully) or a lower-level patch, not a try/catch around the call site. As written, I don't think this actually catches the case it claims to catch — only the os.cpus() pre-check (which is a real synchronous call) is guaranteed to work.

  2. Missing import verification. The diff calls cpus() directly but doesn't show adding import { cpus } from 'os' — if that import isn't already present elsewhere in fingerprint.ts, this won't compile.

Given the crash you're describing is intermittent and hardware-dependent, this really needs a unit test that mocks os.cpus() throwing and systeminformationModule.cpu() rejecting, to prove the guard actually holds. Please clarify with a stack trace from the actual crash showing whether it's a promise rejection or a true uncaught exception - that determines whether this fix is even the right layer.

@codebuff-team codebuff-team added bot:triaged Classified by the community triage bot pr:needs-work Right idea, not mergeable as written labels Sep 18, 2026

This branch has not been deployed

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

Labels

bot:triaged Classified by the community triage bot pr:needs-work Right idea, not mergeable as written

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLI crashes ~3s after start: unhandled Failed to get CPU information from systeminformation on ARM Linux with CPU hotplug skew (Termux/PRoot)

2 participants