URLRequest(url:cachePolicy:timeoutInterval:) started to crash in iOS 26

For a long time our app had this creation of a URLRequest:

var urlRequest = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: timeout)

But since iOS 26 was released we started to get crashes in this call. It is created on a background thread.

Thread 10 Crashed:
0   libsystem_malloc.dylib            0x00000001920e309c _xzm_xzone_malloc_freelist_outlined + 864 (xzone_malloc.c:1869)
1   libswiftCore.dylib                0x0000000184030360 swift::swift_slowAllocTyped(unsigned long, unsigned long, unsigned long long) + 56 (Heap.cpp:110)
2   libswiftCore.dylib                0x0000000184030754 swift_allocObject + 136 (HeapObject.cpp:245)
3   Foundation                        0x00000001845dab9c specialized _ArrayBuffer._consumeAndCreateNew(bufferIsUnique:minimumCapacity:growForAppend:) + 120
4   Foundation                        0x00000001845daa58 specialized static _SwiftURL._makeCFURL(from:baseURL:) + 2288 (URL_Swift.swift:1192)
5   Foundation                        0x00000001845da118 closure #1 in _SwiftURL._nsurl.getter + 112 (URL_Swift.swift:64)
6   Foundation                        0x00000001845da160 partial apply for closure #1 in _SwiftURL._nsurl.getter + 20 (<compiler-generated>:0)
7   Foundation                        0x00000001845da0a0 closure #1 in _SwiftURL._nsurl.getterpartial apply + 16
8   Foundation                        0x00000001845d9a6c protocol witness for _URLProtocol.bridgeToNSURL() in conformance _SwiftURL + 196 (<compiler-generated>:974)
9   Foundation                        0x000000018470f31c URLRequest.init(url:cachePolicy:timeoutInterval:) + 92 (URLRequest.swift:44)#  Live For Studio

Any idea if this crash is caused by our code or if it is a known problem in iOS 26?

I have attached one of the crash reports from Xcode:

Answered by DTS Engineer in 865365022

[For those following along at home, I got a non-corrupted copy of bims’s crash report via other means.]

Consider the crashing thread backtrace:

0  libsystem_malloc.dylib … _xzm_xzone_malloc_freelist_outlined + 864 (xzone_malloc.c:1869)
1  libswiftCore.dylib     … swift::swift_slowAllocTyped(unsigned long, unsigned long, unsigned long long) + 56 …
2  libswiftCore.dylib     … swift_allocObject + 136 (HeapObject.cpp:245)
3  Foundation             … specialized _ArrayBuffer._consumeAndCreateNew(bufferIsUnique:minimumCapacity:growFo…
… …
9  Foundation             … URLRequest.init(url:cachePolicy:timeoutInterval:) + 92 (URLRequest.swift:44)
10 Live                   … Fetcher.fetchData(withPathAndQuery:httpHeaderFields:for:withTimeout:andCompletion:)…

Frame 10 shows your code creating a URLRequest, frames 9 through 3 are it working its way through Foundation, frames 2 and 1 are the Swift runtime, and frame 0 is the system memory allocator.

Unfortunately I just updated my iOS 26 test device to iOS 26.1, so it’s hard to be 100% sure what’s going on here. However, I suspect that iOS 26.1 and 26.0 have basically the same code, and if you disassemble the crashing instruction on iOS 26.1 you see tihs:

(lldb) disas -n _xzm_xzone_malloc_freelist_outlined
libsystem_malloc.dylib`_xzm_xzone_malloc_freelist_outlined:
    …
    0x192a19078 <+828>:  mov    x8, x4
    0x192a1907c <+832>:  stp    x20, x21, [sp, #-0x10]!
    0x192a19080 <+836>:  adrp   x20, 60
    0x192a19084 <+840>:  add    x20, x20, #0xc6c          ; "BUG IN CLIENT OF LIBMALLOC: memory corruption of free block"
    0x192a19088 <+844>:  adrp   x21, 378706
    0x192a1908c <+848>:  add    x21, x21, #0x638          ; gCRAnnotations
    0x192a19090 <+852>:  str    x20, [x21, #0x8]
    0x192a19094 <+856>:  str    x8, [x21, #0x38]
    0x192a19098 <+860>:  ldp    x20, x21, [sp], #0x10
    0x192a1909c <+864>:  brk    #0x1
    …

Note the brk instruction at +864. That gels with this line from your crash report:

Exception Type:  EXC_BREAKPOINT (SIGTRAP)

So, the memory allocator has trapped. And the message at +840 is pretty darned suspicious.

Next, look at thread 11:

Thread 11:
0 libsystem_malloc.dylib  … _xzm_free_abort + 36 (xzone_malloc.c:2311)
1 libsystem_malloc.dylib  … _xzm_free + 1340 (xzone_malloc.c:4739)
2 libsystem_blocks.dylib  … _Block_release + 260 (runtime.cpp:1019)
3 libdispatch.dylib       … _dispatch_client_callout + 16 (client_callout.mm:85)
4 libdispatch.dylib       … <deduplicated_symbol> + 32 (:-1)
5 libdispatch.dylib       … _dispatch_workloop_invoke + 1980 (queue.c:4761)
6 libdispatch.dylib       … _dispatch_root_queue_drain_deferred_wlh + 292 (queue.c:7265)
7 libdispatch.dylib       … _dispatch_workloop_worker_thread + 692 (queue.c:6859)
8 libsystem_pthread.dylib … _pthread_wqthread + 292 (pthread.c:2696)
9 libsystem_pthread.dylib … start_wqthread + 8 (:-1)

Frame 1 shows that some is freeing memory and frame 0 shows that the memory allocator is just about to abort.

So, threads 10 and 11 have both trapped due to memory corruption. That seems like a smoking gun.

As to what’s caused that memory corruption, it’s hard to say. My advice in such situations is to run your program under the standard memory debugging tools. These can help make the problem more reproducible, and reliably reproducing the problem is key to investigations like this.

Oh, and if you have a shiny new iPhone 17, try enabling MTE. That’s can be really helpful in situations like this. See Enabling enhanced security for your app for more.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Something went wrong with you posting your crash report. The crash report says that you crashed on thread 10:

Triggered by Thread:  10

which matches the snippet you posted, but the crash report contains no thread 10 )-:

It’s possible that forums munged it )-: Please download your own crash report and see if it matches what you tried to post. If so, I’d like to get you to file a bug against the forums. But we’ll cross that bridge once we’ve confirmed it’s burning (-:

Regardless, I need to see the full crash report. If you posted the right file and forums is munging it, you’ll need to share it some other way. The best way to do that is to upload it to a file sharing site and then post the URL.

If you run into problems posting the URL, see tip 14 of Quinn’s Top Ten DevForums Tips.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@DTS Engineer thanks for noticing that... arghh, maybe I attached it as 'Text':

:)

@DTS Engineer it seems like .crash-files gets translated into text-file... so I can no longer attach it. I will try to upload it and share a link instead...

[For those following along at home, I got a non-corrupted copy of bims’s crash report via other means.]

Consider the crashing thread backtrace:

0  libsystem_malloc.dylib … _xzm_xzone_malloc_freelist_outlined + 864 (xzone_malloc.c:1869)
1  libswiftCore.dylib     … swift::swift_slowAllocTyped(unsigned long, unsigned long, unsigned long long) + 56 …
2  libswiftCore.dylib     … swift_allocObject + 136 (HeapObject.cpp:245)
3  Foundation             … specialized _ArrayBuffer._consumeAndCreateNew(bufferIsUnique:minimumCapacity:growFo…
… …
9  Foundation             … URLRequest.init(url:cachePolicy:timeoutInterval:) + 92 (URLRequest.swift:44)
10 Live                   … Fetcher.fetchData(withPathAndQuery:httpHeaderFields:for:withTimeout:andCompletion:)…

Frame 10 shows your code creating a URLRequest, frames 9 through 3 are it working its way through Foundation, frames 2 and 1 are the Swift runtime, and frame 0 is the system memory allocator.

Unfortunately I just updated my iOS 26 test device to iOS 26.1, so it’s hard to be 100% sure what’s going on here. However, I suspect that iOS 26.1 and 26.0 have basically the same code, and if you disassemble the crashing instruction on iOS 26.1 you see tihs:

(lldb) disas -n _xzm_xzone_malloc_freelist_outlined
libsystem_malloc.dylib`_xzm_xzone_malloc_freelist_outlined:
    …
    0x192a19078 <+828>:  mov    x8, x4
    0x192a1907c <+832>:  stp    x20, x21, [sp, #-0x10]!
    0x192a19080 <+836>:  adrp   x20, 60
    0x192a19084 <+840>:  add    x20, x20, #0xc6c          ; "BUG IN CLIENT OF LIBMALLOC: memory corruption of free block"
    0x192a19088 <+844>:  adrp   x21, 378706
    0x192a1908c <+848>:  add    x21, x21, #0x638          ; gCRAnnotations
    0x192a19090 <+852>:  str    x20, [x21, #0x8]
    0x192a19094 <+856>:  str    x8, [x21, #0x38]
    0x192a19098 <+860>:  ldp    x20, x21, [sp], #0x10
    0x192a1909c <+864>:  brk    #0x1
    …

Note the brk instruction at +864. That gels with this line from your crash report:

Exception Type:  EXC_BREAKPOINT (SIGTRAP)

So, the memory allocator has trapped. And the message at +840 is pretty darned suspicious.

Next, look at thread 11:

Thread 11:
0 libsystem_malloc.dylib  … _xzm_free_abort + 36 (xzone_malloc.c:2311)
1 libsystem_malloc.dylib  … _xzm_free + 1340 (xzone_malloc.c:4739)
2 libsystem_blocks.dylib  … _Block_release + 260 (runtime.cpp:1019)
3 libdispatch.dylib       … _dispatch_client_callout + 16 (client_callout.mm:85)
4 libdispatch.dylib       … <deduplicated_symbol> + 32 (:-1)
5 libdispatch.dylib       … _dispatch_workloop_invoke + 1980 (queue.c:4761)
6 libdispatch.dylib       … _dispatch_root_queue_drain_deferred_wlh + 292 (queue.c:7265)
7 libdispatch.dylib       … _dispatch_workloop_worker_thread + 692 (queue.c:6859)
8 libsystem_pthread.dylib … _pthread_wqthread + 292 (pthread.c:2696)
9 libsystem_pthread.dylib … start_wqthread + 8 (:-1)

Frame 1 shows that some is freeing memory and frame 0 shows that the memory allocator is just about to abort.

So, threads 10 and 11 have both trapped due to memory corruption. That seems like a smoking gun.

As to what’s caused that memory corruption, it’s hard to say. My advice in such situations is to run your program under the standard memory debugging tools. These can help make the problem more reproducible, and reliably reproducing the problem is key to investigations like this.

Oh, and if you have a shiny new iPhone 17, try enabling MTE. That’s can be really helpful in situations like this. See Enabling enhanced security for your app for more.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hey Quinn and thanks,

I've managed to get an iPhone 17 Pro and enabled MTE, which is super awesome! 🤤 Looking forward to get that on MBPs and iPads...

Not sure how to present the finding other than dumping some screenshots. But here the memory corruption doesn't seem to happen in URLRequest but in the UI stack alone. But I could be wrong 😅

So imagine the three screenshot below glued together...

We are using CATiledLayer. Wondering if it could be related to that...

@DTS Engineer / Quinn, forgot to tag you on my reply yesterday, and so this extra comment today :)

Well, I have limited experience with this myself (gotta get my boss to buy me a shiny new iPhone 17 :-) but I think the best place to start is a crash report. If you detach the debugger from the process, the system should generate one.

For more details on how to do this, and how to post the report here, see Posting a Crash Report.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi @DTS Engineer and thanks :)

I hope that your boss will get you a iPhone 17 😅

I'm trying to attach the ips-file again. I added the.txt extension to make it possible to attach it. I hope it will not screw up and make it an inline text-box when I git 'Reply' 😬

Looking at the ips-file I found that it does not show the finding that Xcode show, e.g., "Thread X: Use of deallocated memory" but it then misses "Memory allocated by Thread 1" and "Memory deallocated by Thread 1", so I am not sure the ips-file is that useful for MTE :(

Looking at the ips-file I found that it does not show the finding that Xcode show

Right. Xcode has MTE smarts beyond what the human readable crash report shows. To see the underlying data, open the JSON crash report and search for memoryErrorReport. With some reformatting you get this:

"memoryErrorReport" : {
  "faultAddress":0x0c00000d9de112c0,
  "blamedAllocation": {
    "size":48,
    "allocationTrace":…,
    "deallocationTrace":…,
    "isFreed":true,
    "address":0x0c00000d9de112c0
  },
  "errorType":"use-after-free"
},

The allocationTrace and deallocationTrace backtraces need further massaging. I did a hack-ish job of that and have included the results at the end of this post.

I wanted the JSON crash report so that I could run it through some internal tools. I was able to do the first part of that today. I was hoping it might point me at some known bugs. It did, but those were resolved a while bug and thus are unlikely to be the cause of this issue.

Unfortunately I’m running into problems applying the other tool. I’ll have to defer that for the moment.

Earlier you wrote:

But here the memory corruption doesn't seem to happen in URLRequest but in the UI stack alone.

Right. I think that’s a MTE doing it’s job, causing the crash to happen earlier, and thus closer to the root cause. And, yeah, those backtraces are pretty solid evidence that this is an Apple problem:

  • Frame 4 of the allocation backtrace shows that the memory was allocated by _UITraitChangeRegistry.
  • Frame 1 of the deallocation backtrace shows that the memory was deallocated by that same class.
  • The crashing thread shows that it’s being accessed by a bunch of UIKit and UIKit adjacent (FrontBoardServices, BaseBoard) libraries.

[Lemme just say, MTE is so cool.]

My best guess is that:

  1. BaseBoard allocated that memory.
  2. And then deallocated it.
  3. UIKit allocated that memory.
  4. And then deallocated it.
  5. BaseBoard then did its use after free.

However, it’s hard to be sure without getting a more detailed memory log (a malloc history).

Honestly, this doesn’t look like your problem. But if you’re still able to reproduce it and you can do that in Xcode, then you could enable malloc history (choose Product > Scheme > Edit Scheme and then enable Run > Diagnostics > Malloc Stack Logging) to learn more.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"


The allocationTrace backtrace looks something like this:

 0 _malloc_type_malloc_outlined
 1 operator_new_impl[abi:ne200100](unsigned long, std::__type_descriptor_t)
 2 $_0::operator()() const::'lambda0'(unsigned long, std::__type_descriptor_t)::__invoke(unsigned long, std::__…
 3 std::__1::pair, void*>*>, bool> std::__1::__hash_table, std::__1::__unordered_map_hasher, std::__1::hash, st…
 4 -[_UITraitChangeRegistry recordTraitUsage:forTraitEnvironment:insideMethod:withInvalidationAction:]
 5 -[UIView _recordTraitUsage:trackedStateDiff:insideMethod:withInvalidationAction:]
 6 -[UIView(AdditionalLayoutSupport) _sendUpdateConstraintsIfNecessaryForSecondPass:]
 7 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:]
 8 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:]
 9 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:]
10 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:]
11 -[NSISEngine withBehaviors:performModifications:]
12 __100-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:]_bl…
13 -[UIView(AdditionalLayoutSupport) _withUnsatisfiableConstraintsLoggingSuspendedIfEngineDelegateExists:]
14 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:]
15 -[UIView _updateConstraintsAtEngineLevelIfNeededWithViewForVariableChangeNotifications:]
16 -[UIView _updateConstraintsAsNecessaryAndApplyLayoutFromEngine]
17 -[UIView(Hierarchy) layoutSubviews]
18 ?
19 ?
20 -[UIView(CALayerDelegate) layoutSublayersOfLayer:]
21 CA::Layer::perform_update_(CA::Layer*, CALayer*, unsigned int, CA::LayerUpdateReason, CA::Transaction*)
22 CA::Layer::update_if_needed_(CA::Transaction*, CA::LayerUpdateReason)
23 CA::Layer::layout_and_display_if_needed(CA::Transaction*)
24 CA::Context::commit_transaction(CA::Transaction*, double, double*)
25 CA::Transaction::commit()
26 CA::Transaction::flush_as_runloop_observer(bool)
27 _UIApplicationFlushCATransaction
28 __setupUpdateSequence_block_invoke_2
29 _UIUpdateSequenceRunNext
30 schedulerStepScheduledMainSectionContinue
31 UC::DriverCore::continueProcessing()
32 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
33 __CFRunLoopDoSource0
34 __CFRunLoopDoSources0
35 __CFRunLoopRun
36 _CFRunLoopRunSpecificWithOptions
37 GSEventRunModal
38 -[UIApplication _run]
39 UIApplicationMain
40 closure #1 in KitRendererCommon(_:)
41 runApp</a><a>(_:)
42 static App.main()
43 static LiveForStudioApp.$main()
44 __debug_main_executable_dylib_entry_point
45 start

The deallocationTrace backtrace looks something like this:

 0 std::__1::pair, void*>*>, bool> std::__1::__hash_table, std::__1::__unordered_map_hasher, std::__1::hash, st…
 1 -[_UITraitChangeRegistry recordTraitUsage:forTraitEnvironment:insideMethod:withInvalidationAction:]
 2 -[UIView _recordTraitUsage:trackedStateDiff:insideMethod:withInvalidationAction:]
 3 -[UIView(CALayerDelegate) drawLayer:inContext:]
 4 tiled_layer_render(_CAImageProvider*, unsigned int, unsigned int, unsigned int, unsigned int, void*)
 5 CAImageProviderThread(unsigned int*, bool)
 6 _dispatch_client_callout
 7 _dispatch_continuation_pop
 8 _dispatch_async_redirect_invoke
 9 _dispatch_root_queue_drain
10 _dispatch_worker_thread2
11 _pthread_wqthread

Phew, I already feel bad asking you again 😅

It turns out that MTE and Malloc Stack Logging cannot be enabled at the same time. But I've tried to enabled Malloc Stack Logging, and then get delayed crash somewhere else.

Unfortunately, I didn't really understand where/what to look for in Xcode. I tried to hit the 'Memory Graph Debug' but then the crash context seemed to get lost... most likely I am doing it wrong...

A little context of our app:

  • An UIPageViewController where you can swipe left/right to see the next/previous image.
  • An UIViewController that has a TileImageView subview
  • TileImageView that shows an image. This view is using CATileLayer.
  • When draw(rect:) is called for a specific tile, we either show a cached tile or send a network request to a local server for the tile data.
  • When the network response is received (callback in draw(rect:) we call the view's draw(rect:) to update with tile.

Now if I scroll through the pages the crash may occur.

As stated before this code was working fine before iOS 26. But of course I am unsure if the callback in draw(rect:) could somehow screw-up if e.g., the TileImageView was deallocated. But we should check for weak-self, etc.

By trying to disable code I've found that if I pull out the code in the callback we still crash, i.e., we don't update the draw(rect:). But if I pull out the actual call we don't crash... wondering why the async network call seems to have this side-effect on this...

URLRequest(url:cachePolicy:timeoutInterval:) started to crash in iOS 26
 
 
Q