anthropics / anthropics/claude-code

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

Ouverte
#88,504 3 commentaires 1 réaction 0 personnes assignées Voir sur GitHub
area:sandbox bug has repro platform:macos
Langage dominant
Python
Étoiles
145k
Forks
23.1k
Métriques de merge des PR
Métriques de PR en attente

Description

## 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.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Piste de recherche

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.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
macos, swift
Domaine
desktop, operating-systems, security
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
Active
Clarté
Clairement spécifiée
Accessibilité débutants
74/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.