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)
1
0
30