The willThrow Tax: A hidden 36x slowdown and 2.1KB memory leak per throw in test frameworks

Context: While fuzzing my encrypted messenger Kalego, I noticed a single core pinned at 100% for over an hour while the other nine sat idle. No crash, no error. I sampled the thread with the macOS sample tool and found the culprit: a global runtime hook intercepting every single throw.

Root Cause: The Swift runtime exposes a writable pointer _swift_willThrow. Apple's test frameworks install their own observers into this slot. On every throw, XCTest bridges the Swift error to an autoreleased NSError, captures the call stack, and accumulates it in memory until the end of the test method.

The Numbers (Measured on M5, Swift 6.3.3, Release):

Plain Executable: 20.5 ns / iteration Swift Testing: 295 ns / iteration (14x slower) XCTest: 749 ns / iteration (36x slower) XCTest under xcodebuild/CI: ~1100 ns (54x slower) The Real Defect (Memory Leak): It's not just slow. Under XCTest, each observed throw leaks ~2.1 KB of memory. 2,000,000 throws in a single test method cost +4,031 MB. At fuzzing scale, this turns a slow test into an instant Out-Of-Memory crash.

The Fixes:

Move the hot loop to a standalone executable (best for fuzzing). Use return nil instead of throw on hot paths. Wrap the loop body in autoreleasepool { } to stop the memory leak. (Advanced/Situational) Safely disable the observer using dlsym and defer (code provided in the full report). Full Report & Reproducible Code: I wrote a complete 12-page report with 21 experiments, the assembly disassembly, and all the reproduction code. You can check the numbers on your own machine here: https://github.com/MagicYassin/xctest-throw-cost

Appreciate any technical feedback👨🏻‍💻☁️☁!

Answered by DTS Engineer in 903829022

Have you filed a bug about this already? If so, what was the bug number?

If you haven’t filed a bug, I recommend that you do so now. It looks like you can reproduce this without Xcode, that is, from the command line using just Swift Package Manager. If so, I recommend that you file your bug against the Swift open source. That way you’ll have more insight into the issue’s state (or you could fix it yourself).

Share and Enjoy

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

Have you filed a bug about this already? If so, what was the bug number?

If you haven’t filed a bug, I recommend that you do so now. It looks like you can reproduce this without Xcode, that is, from the command line using just Swift Package Manager. If so, I recommend that you file your bug against the Swift open source. That way you’ll have more insight into the issue’s state (or you could fix it yourself).

Share and Enjoy

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

Filed it here: FB14267090

Hmmm, that’s not right. FB14267090 is an Apple TV bug filed back in 2024. Can you recheck that number?

ps It’s better to reply as a reply, rather than in the comments; see Quinn’s Top Ten DevForums Tips for this and other titbits.

Share and Enjoy

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

Again, it’s really important that you reply as a reply rather than in the comments. I’m only seeing your comments because of extra-ordinary measures on my part, and those only work up to a point.

It's definitely FB14267090.

No it’s not. I did some internal spelunking and found FB24627080.

Can you check that again in Feedback Assistant? Because if it’s showing you the wrong bug number, that’s something I’d like to escalate.

Anyway, I’m happy to report that this bug has found its way to the right folks. I’ve no info to share as to when the fix will ship, but when that happens you’ll be notified by Feedback Assistant.

Share and Enjoy

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

Quinn, thanks for finding the right number! I checked my dashboard and it's FB24627880. I'm really happy to hear it reached the right folks. Thanks for taking the time to dig into this!

and it's FB24627880.

You mean FB24627080, right? Because FB24627880 is a bug about Final Cut!

ps I avoid minor niggles like this by always copy’n’pasting bug numbers (-:

Share and Enjoy

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

The willThrow Tax: A hidden 36x slowdown and 2.1KB memory leak per throw in test frameworks
 
 
Q