Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlapping accesses to "result", but modification requires exclusive access; consider copying to a local variable in xcode 10

Tags:

ios

swift

open static func PBKDF2(_ password: String, salt: Data,
                        prf: PRFAlg, rounds: UInt32) throws -> Data {
    var result = Data(count:prf.cc.digestLength)
    let passwData = password.data(using: String.Encoding.utf8)!
    let status = result.withUnsafeMutableBytes { (passwDataBytes: UnsafeMutablePointer<UInt8>) -> CCCryptorStatus in
        return CCKeyDerivationPBKDF!(
            PBKDFAlgorithm.pbkdf2.rawValue,
            (passwData as NSData).bytes, 
            passwData.count,
            (salt as NSData).bytes, 
            salt.count,
            prf.rawValue,
            rounds,
            passwDataBytes,
            result.count)
     }

     guard status == noErr else { throw CCError(status) }

     return result
}

result.withUnsafeMutableBytes is giving an error in Xcode 10, In Xcode 9 it is a warning.

like image 634
Heman hijack Avatar asked Jun 07 '18 07:06

Heman hijack


1 Answers

That is a consequence of SE-0176 Enforce Exclusive Access to Memory, which was implemented in Swift 4 and is more strict in Swift 4.2.

The solution is to assign the count to a separate variable:

let count = result.count
let status = result.withUnsafeMutableBytes {
    (passwDataBytes: UnsafeMutablePointer<UInt8>) -> CCCryptorStatus in
        return CCKeyDerivationPBKDF(..., count)
}

or to capture the count in a capture list:

let status = result.withUnsafeMutableBytes { [ count = result.count ]
    (passwDataBytes: UnsafeMutablePointer<UInt8>) -> CCCryptorStatus in
        return CCKeyDerivationPBKDF(..., count)
}

See also Overlapping access warning in withUnsafeMutableBytes in the Swift forum

hamishknight:

withUnsafeMutableBytes(_:) is a mutating method on Data, therefore it requires write access to data for the duration of the call. By accessing data.count in the closure, you’re starting a new read on data which conflicts with the current write access.

Joe_Groff:

You could also capture a copy of data or its count in the closure’s capture list: ...

The capture list gets evaluated and the results captured by value when the closure is formed, before the exclusive access begins, avoiding the overlapping access.

and this comment in the corresponding pull request:

Here an appropriate fix is to copy the count of buffer outside of the closure and pass that to inet_ntop() instead.

Update for Swift 5:

let status = result.withUnsafeMutableBytes { [ count = result.count ]
    (bufferPointer) -> CCCryptorStatus in
    let passwDataBytes = bufferPointer.bindMemory(to: UInt8.self).baseAddress
    return CCKeyDerivationPBKDF(..., passwDataBytes, count)
}
like image 198
Martin R Avatar answered Oct 01 '22 03:10

Martin R