Skip to content

Fix codexbar cost SIGSEGV on Linux (Bundle.allBundles in isRunningTests) - #3059

Merged
steipete merged 2 commits into
steipete:mainfrom
Lucenx9:fix/linux-cost-segfault
Aug 19, 2026
Merged

Fix codexbar cost SIGSEGV on Linux (Bundle.allBundles in isRunningTests)#3059
steipete merged 2 commits into
steipete:mainfrom
Lucenx9:fix/linux-cost-segfault

Conversation

@Lucenx9

@Lucenx9 Lucenx9 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

codexbar cost crashes with SIGSEGV on Linux. usage and sessions are unaffected.

Root cause

CostUsageCustomPricing.isRunningTests and OpenCodexUsageLog.isRunningTests fall back to Bundle.allBundles to detect loaded .xctest bundles:

return Bundle.allBundles.contains { $0.bundlePath.hasSuffix(".xctest") }

On Linux (swift-corelibs-foundation) Bundle.allBundles crashes in _CFIsSwift (via CFBundleGetAllBundlesCFArrayGetCount). The cost command reaches this path during pricing initialization (CostUsageScanner.codexPricingKeyCostUsageCustomPricing.load) as well as when openCodexUsageLogsEnabled is true without OPENCODEX_HOME set (CLICostCommand.loadOpenCodexCostPayloadOpenCodexUsageLog.usageLogURL), so it segfaults before producing output. Under test, XCTestConfigurationFilePath / SWIFT_TESTING is already present in the environment, so isRunningTests returns true earlier — which is why CI/test runs didn't hit it, but the production binary does.

Backtrace (0.53.0, release build):

Thread 5 "codexbar" received signal SIGSEGV, Segmentation fault.
0x0000555556cee939 in _CFIsSwift ()
#1  0x0000555556d44516 in CFArrayGetCount ()
#2  0x0000555556d5bda6 in CFBundleGetAllBundles ()
#3  0x0000555556dc3c66 in Foundation.Bundle.allBundlesRegardlessOfType
#4  0x0000555556dc46b3 in Foundation.Bundle.allBundles
#5  ... CostUsageCustomPricing.isRunningTests (...) at CostUsageCustomPricing.swift:77
#6  ... CostUsageCustomPricing.isRunningTests (...) at CostUsageCustomPricing.swift:50
#7  ... CostUsageCustomPricing.load (...) at CostUsageCustomPricing.swift:52

Fix

Keep the Bundle.allBundles .xctest check on macOS, and on Linux detect the test process from the main executable path instead across both CostUsageCustomPricing and OpenCodexUsageModels. SwiftPM builds Linux test executables with a .xctest suffix, so this keeps the original intent without enumerating bundles:

#if os(macOS)
        return Bundle.allBundles.contains { $0.bundlePath.hasSuffix(".xctest") }
#else
        // Bundle.allBundles crashes on Linux (swift-corelibs-foundation). SwiftPM
        // builds test executables with a `.xctest` suffix, so detect the test
        // process from the main executable instead of enumerating bundles.
        return Bundle.main.executableURL?.path.hasSuffix(".xctest") ?? false
#endif

macOS behavior is unchanged.

Verification

  • Reproduced: codexbar cost --format json --json-only → exit 139 (SIGSEGV), no stdout.
  • Workaround confirmed: XCTestConfigurationFilePath=/tmp/x codexbar cost ... → exit 0, valid JSON (short-circuits isRunningTests at the first environment check, confirming the bug is the Bundle.allBundles fallback).
  • Regenerated CodexParserHash.generated.swift (the parser-hash gate covers the edited CostUsage file).
  • Added Linux regression tests in PlatformGatingTests for CostUsageCustomPricing.load(environment: [:]) and OpenCodexUsageLog.usageLogURL(environment: [:]).
  • Patched Linux release CLI verified (see post-fix details below).

Post-fix verification (patched Linux CLI)

Built locally with Swift 6.3.3 release toolchain on Linux (x86_64) from branch fix/linux-cost-segfault (commit a6b4e3401).

Pure production invocation tested without any test environment flags or workarounds (no XCTestConfigurationFilePath or testing markers set).

Execution summary

Binary Command Exit Code Result
Pre-fix (codexbar 0.53.0) codexbar cost --format json --json-only --days 30 139 (SIGSEGV) Crashed before output
Patched release binary (a6b4e34) CodexBarCLI cost --format json --json-only --days 30 0 Success (24,125 bytes JSON)
Patched release binary (a6b4e34) CodexBarCLI usage --format json --json-only 0 Success

Patched binary version

$ ./CodexBarCLI --version
CodexBar

Redacted cost output (jq summary)

$ ./CodexBarCLI cost --format json --json-only --days 30 | jq 'if type=="array" then map({provider, totals}) else {provider, totals} end'
[
  {
    "provider": "codex",
    "totals": {
      "coverage": {
        "unpriced": 0,
        "unmetered": 0,
        "estimated": 0,
        "priced": 7
      },
      "provenance": "listPriceEstimate",
      "totalTokens": 2434191536,
      "inputTokens": 2426481528,
      "cacheReadTokens": 2369676288,
      "totalCost": 1700.7877880999995,
      "outputTokens": 7710008
    }
  },
  {
    "provider": "claude",
    "totals": {
      "coverage": {
        "unmetered": 0,
        "unpriced": 0,
        "priced": 18,
        "estimated": 0
      },
      "provenance": "listPriceEstimate",
      "totalTokens": 725389906,
      "cacheCreationTokens": 11184029,
      "inputTokens": 33206102,
      "cacheReadTokens": 671916202,
      "totalCost": 702.9057385864,
      "outputTokens": 9083573
    }
  }
]

Fixes #3058

@clawsweeper

clawsweeper Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3361502320

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/CodexBarCore/Vendored/CostUsage/CostUsageCustomPricing.swift Outdated
@Lucenx9
Lucenx9 force-pushed the fix/linux-cost-segfault branch from 3361502 to faf65fc Compare August 19, 2026 01:18
isRunningTests falls back to Bundle.allBundles to detect loaded .xctest
bundles. On Linux (swift-corelibs-foundation) Bundle.allBundles crashes in
_CFIsSwift (via CFBundleGetAllBundles -> CFArrayGetCount), so `codexbar cost`
segfaults before producing output. On Linux, detect the test process from the
main executable path instead: SwiftPM builds test executables with a `.xctest`
suffix, so the intent survives without enumerating bundles. macOS behavior is
unchanged.

Fixes steipete#3058
@Lucenx9
Lucenx9 force-pushed the fix/linux-cost-segfault branch from faf65fc to d9ce35c Compare August 19, 2026 01:24
@clawsweeper clawsweeper Bot added P1 Urgent regression or broken agent/channel workflow affecting real users now. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Aug 19, 2026
@clawsweeper

clawsweeper Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codex review: needs changes before merge. Reviewed August 18, 2026, 10:42 PM ET / August 19, 2026, 02:42 UTC.

ClawSweeper review

What this changes

The PR replaces Linux bundle enumeration in two cost-related test detectors with executable-path detection and adds Linux safety tests.

Regression provenance

Possible regression — probable (reproduction; failure trace). No predecessor PR is attributed.

Merge readiness

⚠️ Needs maintainer review before merge - 3 items remain

Keep open for one focused correction: the platform split addresses both Linux crash call paths and the PR includes real Linux CLI output, but the added regression tests never execute the new fallback because the test process has global test markers.

Priority: P1
Reviewed head: a6b4e3401335a356428e2baf2b4f28942a1429d9

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) The production Linux result is strong, but the added regression tests do not cover the newly introduced fallback.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (live_output): The PR body provides after-fix Linux release-CLI output showing cost changed from SIGSEGV exit 139 to successful JSON output; redact local usage details in any future proof update.
Patch quality 🦐 gold shrimp (3/6) 1 actionable review finding remain.

Verification

Check Result Evidence
Real behavior Verified Sufficient (live_output): The PR body provides after-fix Linux release-CLI output showing cost changed from SIGSEGV exit 139 to successful JSON output; redact local usage details in any future proof update.
Evidence reviewed 5 items Both crash paths are platform-gated: The pricing detector uses executable-path detection outside macOS, and the OpenCodex detector applies the same guard after its environment and XCTest checks.
Both detectors are reachable from cost handling: Custom-pricing loading supplies the pricing fingerprint, while the enabled OpenCodex setting calls usageLogURL before loading that source.
Added tests short-circuit before the new fallback: Passing an empty argument environment does not clear ProcessInfo.processInfo.environment, which each detector checks before the platform branch; the OpenCodex test comment explicitly acknowledges that the test runner's markers cause the early return.
Findings 1 actionable finding [P2] Exercise the Linux fallback outside test markers
Security None None.

Live Verification

Command: swift build -c release

Result: FAIL (failed) — execution before step 1 run: sh -lc pnpm install --ignore-scripts --frozen-lockfile failed: ! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-11.22.0.tgz

sh -lc pnpm install --ignore-scripts --frozen-lockfile failed: ! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-11.22.0.tgz

Assertions:

  • FAIL expect_output: Build complete!
  • FAIL expect_output: [

How this fits together

The cross-platform CLI builds cost summaries from local usage and pricing data. Cost initialization and the optional OpenCodex usage-log source both check whether they are running under tests before touching user-local paths.

flowchart LR
A[Linux cost command] --> B[Cost pricing initialization]
A --> C[Optional OpenCodex log setting]
B --> D[Test-process detection]
C --> D
D -->|macOS| E[Inspect loaded test bundles]
D -->|Linux| F[Inspect executable path]
E --> G[Cost JSON output]
F --> G
Loading

Before merge

  • Exercise the Linux fallback outside test markers (P2) - These tests pass environment: [:], but both detectors also read ProcessInfo.processInfo.environment; Swift Testing supplies markers there, so each returns before the new #else branch. The OpenCodex test comment confirms that short-circuit. Use a controlled detector seam or sanitized subprocess so CI reaches the executable-path fallback and catches a return to Bundle.allBundles.
  • Resolve merge risk (P2) - The automated tests give false confidence for the exact Linux fallback: global test markers make them return before reaching the newly added executable-path branch.
  • Complete next step (P2) - A narrow automated test repair can make CI exercise the two newly added Linux fallback branches before merge.

Findings

  • [P2] Exercise the Linux fallback outside test markers — TestsLinux/PlatformGatingTests.swift:243-255
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Changed surface 4 files affected; production +15/-1, tests +23 The functional change is narrow, with most added lines intended as Linux regression coverage.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #3058
Summary: This PR explicitly implements the reported Linux cost-command crash from the canonical issue.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge-risk options

Maintainer options:

  1. Exercise the real Linux fallback before merge (recommended)
    Replace the marker-short-circuited checks with focused coverage that runs each detector with no global test markers and verifies the cost path returns rather than crashes.
  2. Accept the contributor's live proof
    Merge based on the recorded release-CLI recovery while accepting that CI will not detect a future regression of the two fallback branches.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Replace the Linux tests with deterministic coverage that reaches both non-macOS executable-path fallbacks without ProcessInfo test markers; retain isolated user paths and do not change release-owned CHANGELOG.md.

Technical review

Best possible solution:

Keep the two Linux-safe guards and add a deterministic sanitized-process or injectable detector test that actually reaches each fallback without accessing real user data.

Do we have a high-confidence way to reproduce the issue?

Yes: a Linux release CLI invocation of codexbar cost --format json --json-only is a concrete path, supported by the reported SIGSEGV trace and the two reachable source call chains; this review did not execute it locally.

Is this the best way to solve the issue?

Yes for the implementation: retaining macOS bundle inspection while using the executable path on Linux is the narrowest compatible repair. The regression coverage is not yet the best validation because it short-circuits before the new branch.

Full review comments:

  • [P2] Exercise the Linux fallback outside test markers — TestsLinux/PlatformGatingTests.swift:243-255
    These tests pass environment: [:], but both detectors also read ProcessInfo.processInfo.environment; Swift Testing supplies markers there, so each returns before the new #else branch. The OpenCodex test comment confirms that short-circuit. Use a controlled detector seam or sanitized subprocess so CI reaches the executable-path fallback and catches a return to Bundle.allBundles.
    Confidence: 0.98

Overall correctness: patch is incorrect
Overall confidence: 0.93

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against a32989c750e6.

Labels

Label justifications:

  • P1: A released Linux CLI command currently terminates with SIGSEGV instead of returning a cost summary.
  • merge-risk: 🚨 availability: The patch changes the crash-prone detection path, but its added automated tests do not execute the replacement Linux fallback.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The PR body provides after-fix Linux release-CLI output showing cost changed from SIGSEGV exit 139 to successful JSON output; redact local usage details in any future proof update.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides after-fix Linux release-CLI output showing cost changed from SIGSEGV exit 139 to successful JSON output; redact local usage details in any future proof update.

Evidence

Acceptance criteria:

  • [P1] swift test --filter PlatformGatingTests.
  • [P1] swift build -c release.

What I checked:

Likely related people:

  • Peter Steinberger: The locally available history associates the v0.53.0 release tag and prior contribution in these cost-source files with Peter; the shallow graft prevents stronger attribution. (role: adjacent release and code-area contributor; confidence: low; commits: 5a2a70458d95; files: Sources/CodexBarCore/Vendored/CostUsage/CostUsageCustomPricing.swift, Sources/CodexBarCore/Vendored/OpenCodexUsage/OpenCodexUsageModels.swift)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Add deterministic Linux coverage that reaches both executable-path fallback branches.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (2 earlier review cycles)
  • reviewed 2026-08-19T01:28:26.907Z sha d9ce35c :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-19T01:49:53.068Z sha d9ce35c :: needs changes before merge. :: [P1] Guard the OpenCodex test detector on Linux

@vincent-peng

Copy link
Copy Markdown
Contributor

Deep review found one remaining Linux crash path before merge.

codexbar cost --format json conditionally calls loadOpenCodexCostPayload. When openCodexUsageLogsEnabled is true and OPENCODEX_HOME is unset, OpenCodexUsageLog.usageLogURL reaches OpenCodexUsageLog.isRunningTests, whose final fallback still calls Bundle.allBundles at OpenCodexUsageModels.swift:169. In a normal Linux CLI process NSClassFromString("XCTestCase") is nil, so this can hit the same swift-corelibs-foundation SIGSEGV after the primary custom-pricing fix.

I recommend applying the same platform split there, preserving the existing environment and NSClassFromString checks:

#if os(macOS)
return Bundle.allBundles.contains { $0.bundlePath.hasSuffix(".xctest") }
#else
return Bundle.main.executableURL?.path.hasSuffix(".xctest") ?? false
#endif

The current Linux CI is useful but does not prove recovery: its release smoke runs --help, --version, and usage --web, never cost. A decisive check is the release CLI with all XCTest/Swift Testing markers unset, isolated HOME/CODEX_HOME, exit 0, and parseable JSON. For the OpenCodex route, enable the preference and leave OPENCODEX_HOME unset; setting it bypasses this detector and would create a false-positive smoke.

Independent read-only intent, security, reliability, and coverage reviews all reproduced this call chain. Local focused tests on this head also pass: 6 CostUsageCustomPricingTests and 12 OpenCodexUsageParserTests.

@Lucenx9

Lucenx9 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event exact_review_queue).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

@clawsweeper clawsweeper Bot added merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Aug 19, 2026
@Lucenx9

Lucenx9 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event exact_review_queue).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@steipete
steipete merged commit 1c1defa into steipete:main Aug 19, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. P1 Urgent regression or broken agent/channel workflow affecting real users now. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

codexbar cost segfaults on Linux (0.53.0) via Bundle.allBundles in isRunningTests

3 participants