Skip to content

Conversation

JesusRojass
Copy link
Contributor

Copied response.MIMEType before assigning to responseContentType to avoid EXC_BAD_ACCESS caused by early deallocation under certain network or SDK conditions.

Discussion

Clients state that they where experiencing a crash in FPRNetworkTrace on devices running iOS and iPadOS 17.5.1 and up, its not a 100% reproducible crash but it seems to happen under certain network conditions

After I began to read the stack trace and logs I found out that the root cause is a use after bug that is triggered by accessing response.MIMEType from a possibly deallocated NSURLResponse object inside the didCompleteRequestWithResponse method located inside of FPRNetworkTrace.m


Where the crash happens on the user provided stack trace (EXC_BAD_ACCESS (SIGSEGV) type crash):

0 libsystem_malloc.dylib __CFStringDeallocate 1 CoreFoundation _CFRelease 2 CFNetwork URLResponse::getMIMEType() 3 FPRNetworkTrace didCompleteRequestWithResponse:error:

The MIME type string returned by NSURLResponse.MIMEType is a non retained CoreFoundation owned pointer that may be deallocated if the NSURLResponse instance is no longer strongly referenced or becomes invalid if the delegate method is invoked on a separate queue after the response’s lifecycle ends, without retaining a response, this opens a race condition where response may be freed before MIMEType is accessed.


Possible repro scenarios (Hard to reproduce!!!)

  • Short-lived responses

  • Heavy background thread contention
  • Custom NSURLProtocol setups (That could be Found in AppLovin SDK for example)


Proposed Fix

My proposed fix consists of modifying the assignment of response.MIMEType in -didCompleteRequestWithResponse:error: to defensively copy the value, this will address the crash users had and adds an extra layer of safety when this value is being accessed, and it also doesn’t add or makes a behavioral change to the existing flow also under certain network conditions or when third-party SDKs like AppLovin hook into NSURLSession, the original NSURLResponse instance may be prematurely deallocated or altered, copying the MIME type ensures the string is retained independently on the heap, breaking potential races with early deallocation or thread-unsafe memory access.



Testing

  • Ran repeatedly 1000 Unit tests locally in XCode to check for flakiness with and without network link conditioner on a: iPhone 14 Pro running iOS 18.6.2 and an iPhone SE 3rd Gen Simulator on iOS 18.6.2
  • Code Altered shouldn't edit functionality it's just an extra safety step

Testing Screenshots

iPhone 14 Pro

Screenshot 2025-09-10 at 5 11 22 p m

iPhone SE 3rd Gen Simulator

Screenshot 2025-09-10 at 5 14 32 p m

API Changes

  • No API Change

Copied response.MIMEType before assigning to responseContentType
to avoid EXC_BAD_ACCESS caused by early deallocation under certain
network or SDK conditions.
@JesusRojass JesusRojass marked this pull request as ready for review September 10, 2025 23:16
@paulb777
Copy link
Member

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Thank you for this contribution. The pull request description provides an excellent and detailed analysis of the use-after-free bug, which is very helpful. The fix itself is correct and effectively prevents the crash by copying the MIMEType. I've added one minor suggestion to simplify the implementation slightly by removing a redundant local variable. Overall, this is a great fix.

Comment on lines +254 to +256
// Safely copy MIMEType to prevent use after free
NSString *mime = [response.MIMEType copy];
self.responseContentType = (mime.length ? mime : nil);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @JesusRojass, for investigating! I'm unsure if this approach addresses the issue. The crash happens in the call to MIMEType, so the subsequent copy won't run (3 CFNetwork 0x32c9c URLResponse::getMIMEType() + 60).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still have doubts that this is fixes the crash in the linked issue, but I think this is a great improvement that makes this logic more resilient and explicit, so we can merge as-is and continue to monitor the original issue for any changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have another more defensive idea to address the crash because I never thought of it that way

just waiting on my local unit tests to run before commiting

@ncooke3 ncooke3 merged commit d40913e into firebase:main Sep 11, 2025
47 checks passed
@JesusRojass
Copy link
Contributor Author

@visumickey tag in merged pr

@firebase firebase locked and limited conversation to collaborators Oct 11, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants