Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os_unfair_lock Corruption in HTTPFields Storage Copy Under Concurrent Mutation #86

Open
JeonJiyoun opened this issue Feb 6, 2025 · 8 comments

Comments

@JeonJiyoun
Copy link

Summary

We are encountering a crash due to an _os_unfair_lock_corruption_abort in the HTTPFields._Storage.copy() method from the Swift HTTP Types package. The crash appears to be related to concurrent mutations of an HTTPFields instance when used in our dynamic XCFramework. This issue seems to occur when the copy-on-write (COW) mechanism (using isKnownUniquelyReferenced) does not properly handle concurrent access, causing the internal os_unfair_lock to become corrupted.

Description

Our project uses Swift HTTP Types for managing HTTP header fields (via the HTTPFields struct). In our usage, we update header fields in our middleware which eventually calls into the subscript setter of HTTPFields and invokes setFields(_:). Internally, this causes a copy-on-write operation on the _Storage class.

The _Storage class uses an os_unfair_lock (allocated via an UnsafeMutablePointer<os_unfair_lock>) to protect its internal index and fields. During a call to _Storage.copy(), we observe that the lock is corrupted, leading to a call to _os_unfair_lock_corruption_abort.

A brief excerpt from our stack trace is as follows:

Thread 5 Queue : com.apple.root.user-initiated-qos.cooperative (concurrent)
#0  0x00000001f691c220 in _os_unfair_lock_corruption_abort ()
#1  0x00000001f6919578 in _os_unfair_lock_lock_slow ()
#2  0x000000010367fc2c in HTTPFields._Storage.copy() at HTTPFields.swift:92

Our current hypothesis is that when the same HTTPFields instance is mutated concurrently by multiple threads, the copy-on-write mechanism (which checks uniqueness via isKnownUniquelyReferenced) does not provide proper synchronization. This concurrent access causes the internal os_unfair_lock to be used in an unsafe manner (or even be copied), eventually resulting in the reported corruption.

Steps to Reproduce

1.	Use the Swift HTTP Types package (via SPM) along with Swift Open API Runtime.
2.	Integrate these packages into a dynamic XCFramework.
3.	In a scenario where header fields (using HTTPFields) are mutated concurrently—for example, in a middleware that updates header fields from multiple concurrent operations—observe that the app crashes with _os_unfair_lock_corruption_abort.

Note: Building as a static XCFramework is not viable due to duplicate symbol errors, which forces us to use a dynamic XCFramework.

Expected Behavior

HTTPFields should be safe to use in concurrent scenarios or should at least clearly document that instances must not be mutated concurrently. Alternatively, internal synchronization (or a different COW strategy) might be needed to prevent the os_unfair_lock from becoming corrupted when a copy is triggered under concurrent mutations.

Workaround

Until a fix is provided, we are serializing access to any shared HTTPFields instance in our middleware to avoid concurrent mutations. This has mitigated the issue in our code but may not be ideal in all use cases.

Additional Context

•	We have verified that the crash occurs in HTTPFields._Storage.copy() during the locking operation.
•	The problem may be exacerbated by the fact that our project uses a dynamic XCFramework, leading to potential multiple loads or copies of the same SPM package code.

Any guidance or fixes on making the copy-on-write mechanism (and the use of os_unfair_lock) in HTTPFields safe under concurrent access would be greatly appreciated.

Thank you for your attention to this matter.

@Lukasa
Copy link

Lukasa commented Feb 6, 2025

Thanks for filing this issue. Can you show us the usage site of the HTTP fields? I'm concerned that this is more likely to be a thread-safety issue in user code.

@Lukasa
Copy link

Lukasa commented Feb 6, 2025

To elaborate, if you have written a middleware that operates concurrently from multiple threads, you must not mutate a stored HTTPFields object from concurrent threads without synchronization. Swift 6 mode will diagnose this for you immediately.

@JeonJiyoun
Copy link
Author

Hi,

Thank you for your response.

After further investigation, we found that even when we comment out all direct usage of HTTPFields in our own code, the crash still occurs within the Swift OpenAPI Runtime module. Specifically, the crash occurs when the OpenAPI Generator–produced code is built into a dynamic XCFramework and integrated into our project.

Here are our observations:
• Direct Import / Project Integration: When we import the Swift OpenAPI Runtime directly or add the generated code to our Xcode project, we do not observe any crashes.
• Dynamic Framework Integration: The crash reliably reproduces only when we build and integrate the generated code as a dynamic XCFramework. In this case, the crash appears to occur during the copy-on-write operation within HTTPFields, likely due to issues with dynamically loaded code and potential multiple instances or unsynchronized access of the Swift HTTP Types package.

These findings suggest that the issue is not due to our middleware mutating HTTPFields from multiple threads without proper synchronization, but rather it seems to be related to the dynamic framework loading mechanism. It appears that in this scenario, the internal os_unfair_lock within HTTPFields may be subject to concurrent access issues or even duplication, leading to the reported lock corruption.

Since using dynamic frameworks is necessary for our project (due to duplicate symbol issues with static frameworks), we are looking for a more robust solution.

Could you provide any additional guidance on:
• Whether there are recommended practices for integrating these modules(related to the swift open api generator) as dynamic frameworks?
• Potential workarounds or fixes in the Swift HTTP Types package that could help address this concurrency issue in a dynamic framework context?

Thank you for your attention and assistance.

@czechboy0
Copy link

Can you say more about how you're building the xcframework(s)? swift-http-types and swift-openapi-runtime are two distinct modules, are you building two distinct xcframeworks? Or are you building both modules into the same xcframework?

@JeonJiyoun
Copy link
Author

OK. Thanks for your reply.

Background

When I imported the Swift Open API Generator plugin directly into my Xcode project, I experienced significantly long build times. As a workaround, I set up a separate project where the generator produces the code, and I used an automation script to copy the generated code into my main project.

Building xcframework

However, due to the enormous size of the Types.swift file—and the considerable time required to build it—I ultimately opted to build the separate project as a dynamic xcframework. I then imported this xcframework into my main project.

I’ve attached the folder structure of that project for reference. As you can see, it includes dependencies for the Open API runtime-related packages, along with the generated code from the Open API generator.

Image

@czechboy0
Copy link

Are you using all of the operations from the OpenAPI document in your code? If not, you might instead want to opt into using filtering, and only generate/compile what you're using. That usually helps with the build time concerns.

Since both Swift HTTP Types and Swift OpenAPI Runtime produce public APIs, it will be tricky to build individual xcframeworks and get it all working. I'd strongly recommend sticking with the plugin (or manual generation), rather than building the xcframework as a way to speed up builds.

@JeonJiyoun
Copy link
Author

I’m already using the filtering you mentioned. Nevertheless, since I work with a large number of APIs, I tried applying an xcframework to further improve things. So, is there currently no way to resolve this issue—and none expected in the future either? If that’s the case, I’ll go ahead and use the recommended approach. However, as you agree, build times are a critical concern for developers, so it would be great if there were any further improvements available by any other means. Thank you.

@czechboy0
Copy link

Build times and caching are being looked at by the folks working on SwiftPM, as it affects all packages. But yes, in the meantime, I'd recommend avoiding the xcframework. cc @dschaefer2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants