Learning Swift on macOS, struggling with acl_free

I'm converting some code that reads a file's ACLs and I'm having a hard time with acl_free crashing. There is clearly something that I am not understanding.

// --- Do we have access control lists?
let fileSecurity = properties.fileSecurity
var accessList: acl_t?

if CFFileSecurityCopyAccessControlList( fileSecurity, &accessList ) {
     print( "We have access control lists" )
     acl_free( &accessList )
}

The line acl_free( &accessList ) crashes with the following.

malloc: *** error for object 0x16d28ac40: pointer being freed was not allocated

In the debugger I can see that accessList points to an object.

"accessList = acl_t? 0x000000015b00ea00"

I notice that the crash report ptr ref is different to what Xcode is showing in the debugger.

Also worth noting, is CFFileSecurityCopyAccessControlList takes a "UnsafeMutablePointer<acl_t?>!"

While acl_free takes a "void *obj_p"

Can anyone please give me a ptr as to what I am doing wrong?

16" MacBook Pro M2 Pro with Ventura 13.5 running Xcode 15.0

Replies

Learning Swift on macOS, struggling with acl_free

It’s like you went out of your way to choose one of weirdest dark’n’dusty corners of the ecosystem. Why couldn’t you just create a SwiftUI app like everyone else (-:

Anyway, the reason you’re crashing is that your pointers don’t line up. It’s especially challenging because of the weird way that the ACL API is constructed in C. And your attempts to fix that have run across a common pitfall: Ampersand (&) doesn’t do what you think it does. See The Peril of the Ampersand for the full backstory.

Here’s some code that works:

import Foundation

func main() throws {
    let u = URL(fileURLWithPath: "/Users/quinn")
    let r = try u.resourceValues(forKeys: [.fileSecurityKey])
    let s = r.fileSecurity!
    var aclQ: acl_t? = nil
    let success = CFFileSecurityCopyAccessControlList(s, &aclQ)
    guard success, let acl = aclQ else { fatalError() }

    if let c = acl_to_text(acl, nil) {
        print(String(cString: c))
        acl_free(c)
        // prints:
        // !#acl 1
        // group:ABCDEFAB-CDEF-ABCD-EFAB-CDEF0000000C:everyone:12:deny:delete
    }

    acl_free(UnsafeMutableRawPointer(acl))
}

try main()

There are a number of subtleties here:

  • let acl = aclQ — I’m doing this so that acl is non-optional throughout the rest of the function. That just makes everything easier.

  • acl_free(UnsafeMutableRawPointer(acl)) — In C, acl_free is ‘generic’: It can free a variety of different data structures returned by the ACL API. In Swift that means it gets imported as taking an UnsafeMutableRawPointer. However, the type of acl is acl_t [1]. So, you have to apply a manual conversion.

  • acl_free(c) — Note how you don’t need the conversion here. That’s because c is of type UnsafeMutablePointer<CChar>, and Swift has a built-in conversion from that to UnsafeMutableRawPointer.

Share and Enjoy

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

[1] This is actually a type alias for OpaquePointer, which is the source of ongoing grief in the Swift/C interop story. There have been various efforts to fix this but none of them have stuck. Indeed, it just came up again on Swift Forums.

  • Superb eskimo... Once again you've saved my bacon. I wasn't trying to find a challenge, I already have enough just trying to learn Swift and SwiftUI.

    I think I understand, when the object is NOT a UnsafeMutablePointer, I should cast it to be a UnsafeMutablePointer, unless the documentation states otherwise.

    I have filed a Feedback Request to get your example added to the documentation for CFFileSecurityCopyAccessControlList as I think it would help other developers.

    Thank you again.

Add a Comment