Shopify / Shopify/react-native-skia
[iOS] SIGABRT in makeImageSnapshot when canvas size is -1 — MTLTextureDescriptor width (uint64)-1 assertion
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().RNSkJsiViewApidispatches 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) constructsRNSkOffscreenCanvasProviderwith_canvasProvider->getWidth()/getHeight()without any size validation, so-1flows straight intomakeOffscreenSurface.
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
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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