I’m losing my mind trying to call zlib from Swift. I’ve ported some C++ code of mine that’s known to work, and I think I have a decent grasp of the twisty maze of unsafe-pointer types, but I’m getting errors back from every call to deflate that basically mean “your context struct is bad”.
After breaking on the entry points of deflateInit2_ and deflate and looking at the registers, I find that the z_stream pointer in $x0 is not the same from call to call. The struct contents at the address are correct, but it’s as though the struct is being copied. I strongly suspect that zlib does not like its struct being moved around and that’s the reason for the error.
Here I should point out that the C z_stream is a member of my Swift struct, which is ~Copyable. So that should prevent Swift from making copies, right?
import zlib
struct ZlibStream: ~Copyable { // highly simplified
var stream = z_stream()
init() { deflatInit2_(&stream, ...) }
}
Moreover, I can see this in Swift by printing the address of the stream member:
withUnsafePointer(to: self.stream) { zPtr in
print("stream is at \(zPtr)")
}
When I call this at different times I get three different results:
- In the struct’s init method
- In the function that created my struct
- When my struct makes a call to
deflate
Is there something deeply weird about having a C struct as a member of a Swift struct? Is Swift somehow forced to make a temporary copy of the struct every time it references it?
By comparison, I’ve found code nearly identical to mine in the swift-gzip library. The only difference is that the z_stream is a local variable of a function, not a member of a struct. I can’t do this, though, because I have to make multiple calls to the stream across async events.
(Platform details: Swift 6.3, Xcode 26.4, Apple Silicon MBP.)