anthropics / anthropics/claude-code

iOS Simulator panel crash-loops on macOS 27 beta: seatbelt profile denies Metal's new cache-dir writes

オープン
#88,504 コメント 3 件 リアクション 1 件 担当者 0 名 GitHub で見る
area:sandbox bug has repro platform:macos
主要言語
Python
スター
145k
フォーク
23.1k
PR マージ指標
PR 指標を取得中

説明

## Environment
- Claude desktop app **1.34493.1** (macOS), iOS Simulator panel (`claude-ios-sim` helper)
- **macOS 27.0 beta (26A5416b)**, Apple Silicon
- Xcode 26.6 release selected (`xcode-select`), iOS 26.0 simulator runtime booted

## Summary
On macOS 27 beta 26A5416b, the Claude Code iOS Simulator panel crashes within seconds of every attach — the sidecar exits, the supervisor relaunches it, and after a few cycles it gives up ("stopped retrying after repeated crashes"). The crash is an uncaught `NSInvalidArgumentException` inside Metal while CoreImage initializes, and the root cause is an interaction between the helper's seatbelt profile (`Claude.app/Contents/Resources/claude-ios-sim.sb`) and new Metal behavior in this macOS beta.

## Crash signature
Every `.ips` for `claude-ios-sim` shows the same last-exception backtrace:

```
*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]

CoreFoundation -[__NSPlaceholderArray initWithObjects:count:]
CoreFoundation +[NSArray arrayWithObjects:count:]
Metal __39-[_MTLDevice recordBinaryArchiveUsage:]_block_invoke
libdispatch _dispatch_once_callout
Metal -[_MTLDevice recordBinaryArchiveUsage:]
Metal -[_MTLBinaryArchive loadFromURL:error:]
Metal -[_MTLBinaryArchive initWithOptions:device:url:error:]
CoreImage +[CIKernelLibrary(Internal) internalBinaryArchiveWithName:device:]
CoreImage CI::PrecompiledUberFunctions::PrecompiledUberFunctions(CI::MetalContext const*)
```

It fires the moment the frame stream opens (first CoreImage/Metal context in the helper).

## Root cause
On 26A5416b, Metal's `recordBinaryArchiveUsage:` **writes usage data under `DARWIN_USER_CACHE_DIR`** (`/var/folders/.../C/`) when CoreImage loads its precompiled kernel archive. The seatbelt profile only allows writes to the CoreSimulator dirs, `DARWIN_TMP`, and `/private/var/tmp` — the user cache dir is denied. The denied handle surfaces as a `nil` in an `NSArray` literal inside the `dispatch_once` block, and the helper aborts.

Verified by bisection with a minimal repro:

```swift
// ci_repro.swift — crashes under the profile, renders fine without it
import CoreImage
import Metal
let dev = MTLCreateSystemDefaultDevice()!
let ctx = CIContext(mtlDevice: dev)
let img = CIImage(color: .red).cropped(to: CGRect(x: 0, y: 0, width: 8, height: 8))
_ = ctx.createCGImage(img, from: img.extent)
print("CI+Metal render OK")
```

- Run plain: **renders OK**.
- Run via `sandbox-exec -f claude-ios-sim.sb` (same `-D` params the app passes, binary placed inside `HELPER_BUNDLE` so `process-exec` allows it): **crashes with the exact signature above**.
- Same sandboxed run with one appended rule — `(allow file-write* (subpath ""))` — **renders OK**.

Narrower candidates were tested and do *not* fix it (so it's the cache-dir write, not a read): allowing full `$HOME` `file-read-data` doesn't help; `CI_USE_SOFTWARE_RENDERER=1` doesn't help (the helper creates its `CIContext` with an explicit Metal device).

## Suggested fix
Add the user cache directory to the profile's write allow-list, e.g.:

```scheme
;; macOS 27 beta: Metal records binary-archive usage under the user cache dir
(allow file-write* (subpath (param "DARWIN_CACHE")))
```

with `DARWIN_CACHE` resolved from `confstr(_CS_DARWIN_USER_CACHE_DIR)` alongside the existing `DARWIN_TMP` param in the sidecar spawn code. Cache-dir scratch seems consistent with the profile's stated intent ("CoreSimulator device state and scratch only").

## Notes for triage
- The failure is invisible in the app UI beyond generic "sidecar exited (code=134)" / crash-loop messages; the `.ips` files carry the signature.
- A second, related trap found while investigating: the profile's `process-exec` allow-list (helper bundle, `/usr/bin`, `/usr/libexec`, Xcode, `/Library/Developer`) means an exec of `/bin/zsh` etc. exits 71 with **no crash log at all** — worth a clearer supervisor message distinguishing "exec denied" from a real crash.
- Local workaround applied on this machine: the one-line profile addition above (byte-exact original preserved). Happy to test a fixed build.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

Start with Claude.app/Contents/Resources/claude-ios-sim.sb and the sidecar spawn code that supplies DARWIN_TMP; compare the existing sandbox parameters with confstr(_CS_DARWIN_USER_CACHE_DIR). Run ci_repro.swift under the profile, then verify the helper renders without crashing and the iOS Simulator panel no longer enters its crash loop.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
macos, swift
領域
desktop, operating-systems, security
issue の種類
バグ
難易度
3/5
見積もり時間
1〜2日
活発さ
活発
明瞭さ
明確に書かれている
初心者へのやさしさ
74/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。