Search code examples
swiftopensslpass-by-referenceswift3unsafe-pointers

How to pass an UnsafePointer<UInt8> to a C API by reference?


I wrote some Swift 2.2 code to interact with OpenSSL C APIs and now I'm trying to convert it to Swift 3.

In Swift 2

let octets = pkcs7_d_data(pkcs7_d_sign(receiptPKCS7).memory.contents)
var ptr = UnsafePointer<UInt8>(octets.memory.data)

// now pass pointer by reference
ASN1_get_object(&ptr, &length, &type, &xclass, end - ptr)

In Swift 3, I've had to make a couple changes

// use guard so i dont have to constantly unwrap these values

guard let octets = pkcs7_d_data(pkcs7_d_sign(receiptPKCS7).pointee.contents),
      var ptr = UnsafePointer<UInt8>(octets.pointee.data) else {
    return nil
}

ASN1_get_object(&ptr, &length, &type, &xclass, end - ptr)
//              ^^^ this is now a compiler error

Unfortunately, I can no longer pass ptr to ASN1_get_object by reference, due to this error:

Cannot pass immutable value as inout argument: Implicit conversion from UnsafePointer<UInt8> to UnsafePointer<UInt8>? requires a temporary

and then the rest of the error is cut off (there's no expand arrow).

What I've tried:

  • changing the ptr assignment to UnsafePointer<UInt8>(octets.pointee.data)? but then I'm told that my existing assignment already produces an optional
  • changed the UnsafePointer to UnsafeMutablePointer

What needs to change here?


Solution

  • The problem seems to be that octets.pointee.data is a UnsafeMutablePointer<UInt8>!, but ASN1_get_object expects the address of a UnsafePointer<UInt8>?.

    The following code compiles, but I could not test it:

    if
        let octets = pkcs7_d_data(pkcs7_d_sign(receiptPKCS7).pointee.contents),
        let data = octets.pointee.data {
    
        var ptr: UnsafePointer? = UnsafePointer(data) // (*)
        var length = 0
        var tag: Int32 = 0
        var xclass: Int32 = 0
    
        ASN1_get_object(&ptr, &length, &tag, &xclass, Int(octets.pointee.length))
    }
    

    (*) is the pointer conversion which makes it compile.