Recurring fatal crash inside PDFKit's private tile-rendering pool. Exception is EXC_BREAKPOINT trapped inside CFRelease.cold.2, called from -[PDFTileSurface releaseSurface], reached via -[PDFTilePool releasePDFTileSurface:] <- -[PDFPageLayerTile dealloc]. Symptom matches an over-release / stale-reference bug in PDFTilePool's internal bookkeeping, not app-level misuse. This is a DIFFERENT app/codebase than the one already reported in Developer Forums thread 837282 (https://developer.apple.com/forums/thread/837282?answerId=896871022#896871022), hitting the identical 3-frame private call chain. That report used PDFView + a PKCanvasView overlay and speculated PencilKit/DYDisplayLinkInterposer overlay timing might be a factor. Our app uses a plain PDFView with NO PencilKit/PKCanvasView overlay of any kind, which rules that out as a necessary trigger -- the bug reproduces on stock PDFKit alone. Crash signature (symbolicated, from production Crashlytics): #0 CFRelease.cold.2 #1 CFEqual (also seen as plain CFRelease in the other report -- same release path) #2 -[PDFTileSurface releaseSurface] #3 -[PDFTilePool releasePDFTileSurface:] #4 -[PDFPageLayerTile dealloc] ... (see "Independent trigger paths" below for what appears above frame #4) blameFrame: CFRelease.cold.2, CoreFoundation, owner: PLATFORM (Crashlytics-attributed, no app frames anywhere in the crashing thread across any sample). Independent trigger paths observed (all converge on the same 3-frame chain above):
- Async tile-render completion (our most common variant, ~57% of our occurrences): -[PDFPageLayerTile recievePDFTileSurface:] -> -[PDFPageLayer tileDrawingComplete:] -> old tiles array dealloc -> -[PDFPageLayerTile dealloc] -> ... -> CFRelease.cold.2
- Page-turn animation completion: -[PDFDocumentViewController pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:] -> -[PDFPageView clearTiles] -> -[PDFPageLayer _releaseTiles] -> -[__NSArrayM removeAllObjects] -> -[PDFPageLayerTile dealloc] -> ... -> CFRelease.cold.2
- CATransaction commit / layer teardown: CA::Transaction::commit() -> CA::release_root_if_unused(...) -> CA::release_objects(...) -> -[PDFPageLayerTile dealloc] -> ... -> CFRelease.cold.2
- (from forum thread 837282, different app) UIScrollView content-offset smooth scroll: -[UIScrollView setContentOffset:] -> smooth-scroll display link -> autorelease pool drain -> -[PDFPageLayerTile dealloc] -> ... -> CFRelease.cold.2
Four independent call sites funneling into the same release path strongly suggests the bug is inside PDFTilePool/PDFTileSurface's own reference counting, not any one caller's usage pattern. Diagnostic instrumentation (our own investigation, not yet submitted anywhere): We swizzled -[PDFTileSurface releaseSurface] in a debug build and logged every call (thread, surface pointer identity, re-entrancy count via a weak-keyed NSMapTable) during normal PDF navigation (page turns, scroll, zoom) on an affected device model. Across all observed calls: every surface was released exactly once, always on the main thread -- no Objective-C-level double-call or cross-thread race was observed at the releaseSurface entry point itself. This suggests the over-release is not "PDFTilePool calling release twice" but more likely a race between PDFTilePool's single, correctly-ordered release call and a separate system-level reclaim of the tile's backing store (e.g. IOSurface/purgeable memory eviction under memory pressure) that PDFTilePool's bookkeeping doesn't account for -- consistent with the device skew below. Device / OS distribution (production Crashlytics, 90-day window, 51 events, ~37 impacted users):
- iPad12,1 (iPad 9th gen): 45 events (88%)
- iPad11,7 (iPad 8th gen): 4 events
- iPad15,4 (iPad Air 11" M3): 1 event
- iPad11,4 (iPad Air 3rd gen): 1 event
- 100% on iPadOS 26.5.0 within this window
This matches forum thread 837282's own report of "iPad 8, iPad 9 ... lower-end devices heavily affected" on iOS 26.4.2/26.5, "not affected on iOS 18.x" -- independent corroboration from two unrelated codebases of a regression concentrated on lower-RAM iPads specifically on 26.x. Expected Result: PDFKit's internal tile pool releases each rendered tile surface exactly once and does not trap inside CFRelease regardless of memory pressure, device tier, or which internal code path (render-complete, page-turn, layer-commit, scroll) triggers the release. Actual Result: App crashes with EXC_BREAKPOINT inside CFRelease.cold.2 during ordinary PDF viewing (page turns, scrolling, or async tile-render completion), concentrated on lower-RAM iPads (iPad 8th/9th gen) running iPadOS 26.4.2/26.5. Configuration:
- Plain PDFView (paged, .singlePage, displayDirection .horizontal), no PKCanvasView/PencilKit
- Affected iPadOS versions: 26.4.2, 26.5 (not reproduced on iOS 18.x per forum thread)
- Most affected devices: iPad 8th/9th generation (3GB RAM tier)
Related report: https://developer.apple.com/forums/thread/837282?answerId=896871022#896871022 (same 3-frame private call chain, different app, DTS could not reproduce with vanilla PDFKit+PencilKit under stress testing as of that thread; no FB filed there yet)
Thanks for the detailed write-up.
This crash signature, the -[PDFPageLayerTile dealloc] release path trapping in CFRelease.cold.2, is the same one already under discussion in thread 837282, which you linked. To keep the investigation in one place, I'd suggest following along there.
It is also worth filing a bug report through Feedback Assistant, with a symbolicated crash log and the device and OS distribution you collected. If you post the Feedback ID here, I can refer to it.
https://developer.apple.com/forums/thread/837282 https://developer.apple.com/feedback-assistant/