Shopify / Shopify/react-native-skia

[iOS] SIGABRT in makeImageSnapshot when canvas size is -1 — MTLTextureDescriptor width (uint64)-1 assertion

Open Beginner friendly
#4,029 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
8.6k
Forks
647
Avg merge
1d 17h
Merged PRs (30d)
35

Description

Description

We are seeing a production iOS crash (SIGABRT) in RNSkView::makeImageSnapshot. When the Skia view's canvas size is -1 (view not yet laid out, or being detached), the size is passed without validation into the offscreen surface creation, and Metal aborts on texture descriptor validation:

failed assertion `Texture Descriptor Validation
MTLTextureDescriptor has width (18446744073709551615) greater than the maximum allowed size of 32768.
MTLTextureDescriptor has height (18446744073709551615) greater than the maximum allowed size of 32768.'

18446744073709551615 is (uint64)-1, i.e. the unlaid-out canvas size cast to unsigned.

Stack trace (symbolicated, production)

Metal                -[MTLTextureDescriptorInternal validateWithDevice:]  (failed assertion → abort)
AGXMetalG18P         -[AGXTexture initWithDevice:desc:isSuballocDisabled:]
NOVA                 OffscreenRenderContext::OffscreenRenderContext (MetalContext.h:33)
NOVA                 MetalContext::MakeOffscreen (MetalContext.h:51)
NOVA                 RNSkia::RNSkOffscreenCanvasProvider::RNSkOffscreenCanvasProvider (RNSkView.h:77)
NOVA                 RNSkia::RNSkView::makeImageSnapshot (RNSkView.h:207)
NOVA                 lambda in RNSkJsiViewApi.h:241  (makeImageSnapshotAsync main-queue block)
libdispatch          _dispatch_main_queue_drain

Analysis

  • JS calls canvasRef.makeImageSnapshotAsync(). RNSkJsiViewApi dispatches the actual snapshot to the main queue (RNSkJsiViewApi.h:241).
  • Between the JS call and the main-queue block executing, the view's layout state can change (view detached / not yet laid out) — so JS-side guards (checking onLayout completion / mount state before calling) cannot fully prevent this; it is a native-side TOCTOU.
  • RNSkView::makeImageSnapshot (cpp/rnskia/RNSkView.h) constructs RNSkOffscreenCanvasProvider with _canvasProvider->getWidth()/getHeight() without any size validation, so -1 flows straight into makeOffscreenSurface.

No deterministic repro (production crash on app-store build; the window is a race between snapshot dispatch and view teardown/layout). Not found among existing issues.

Suggested fix

Early-return nullptr when the canvas size is not positive. nullptr already flows into the existing "Failed to make snapshot from view." promise rejection, which callers can handle gracefully:

sk_sp<SkImage> makeImageSnapshot(SkRect *bounds) {
  if (_canvasProvider->getWidth() <= 0 || _canvasProvider->getHeight() <= 0) {
    return nullptr;
  }
  ...

We are running exactly this as a local patch on 2.10.1 and it degrades the crash into the already-handled rejection path. Happy to open a PR if useful.

Environment

  • @shopify/react-native-skia: 2.10.1
  • react-native: 0.86.0 (new arch), Expo SDK 57
  • iOS (observed on iPhone / AGXMetalG18P), production build

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read cpp/rnskia/RNSkView.h at makeImageSnapshot and trace the dimensions into RNSkOffscreenCanvasProvider; review RNSkJsiViewApi.h:241 and the existing snapshot rejection path. Add the non-positive-size guard described in the issue, then verify that invalid canvas sizes reject gracefully instead of reaching Metal texture creation.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, ios, react-native
Domain
computer-graphics, mobile
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.