Merge pull request #421 from mpretty-cyro/fix/memory-management

Further memory management fixes
pull/1062/head
Morgan Pretty 4 weeks ago committed by GitHub
commit bfa94d9974
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -151,7 +151,7 @@ public extension Crypto.Generator {
guard didDecrypt else { throw MessageReceiverError.decryptionFailed } guard didDecrypt else { throw MessageReceiverError.decryptionFailed }
// We need to manually free 'maybePlaintext' upon a successful decryption // We need to manually free 'maybePlaintext' upon a successful decryption
defer { maybePlaintext?.deallocate() } defer { free(UnsafeMutableRawPointer(mutating: maybePlaintext)) }
guard guard
plaintextLen > 0, plaintextLen > 0,

@ -59,7 +59,7 @@ public extension Crypto.Generator {
let ciphertext: Data = maybeCiphertext.map({ Data(bytes: $0, count: ciphertextLen) }) let ciphertext: Data = maybeCiphertext.map({ Data(bytes: $0, count: ciphertextLen) })
else { throw MessageSenderError.encryptionFailed } else { throw MessageSenderError.encryptionFailed }
maybeCiphertext?.deallocate() free(UnsafeMutableRawPointer(mutating: maybeCiphertext))
return ciphertext return ciphertext
} }
@ -98,9 +98,7 @@ public extension Crypto.Generator {
) )
let encryptedData: Data? = cEncryptedDataPtr.map { Data(bytes: $0, count: outLen) } let encryptedData: Data? = cEncryptedDataPtr.map { Data(bytes: $0, count: outLen) }
cMessages.forEach { $0?.deallocate() } free(UnsafeMutableRawPointer(mutating: cEncryptedDataPtr))
cRecipients.forEach { $0?.deallocate() }
cEncryptedDataPtr?.deallocate()
return try encryptedData ?? { throw MessageSenderError.encryptionFailed }() return try encryptedData ?? { throw MessageSenderError.encryptionFailed }()
} }
@ -145,7 +143,7 @@ public extension Crypto.Generator {
let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) }) let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) })
else { throw MessageReceiverError.decryptionFailed } else { throw MessageReceiverError.decryptionFailed }
maybePlaintext?.deallocate() free(UnsafeMutableRawPointer(mutating: maybePlaintext))
return (plaintext, String(cString: cSenderSessionId)) return (plaintext, String(cString: cSenderSessionId))
} }
@ -187,7 +185,7 @@ public extension Crypto.Generator {
let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) }) let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) })
else { throw MessageReceiverError.decryptionFailed } else { throw MessageReceiverError.decryptionFailed }
maybePlaintext?.deallocate() free(UnsafeMutableRawPointer(mutating: maybePlaintext))
return (plaintext, String(cString: cSenderSessionId)) return (plaintext, String(cString: cSenderSessionId))
} }
@ -219,7 +217,7 @@ public extension Crypto.Generator {
let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) }) let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) })
else { throw MessageReceiverError.decryptionFailed } else { throw MessageReceiverError.decryptionFailed }
maybePlaintext?.deallocate() free(UnsafeMutableRawPointer(mutating: maybePlaintext))
return plaintext return plaintext
} }
@ -250,7 +248,7 @@ public extension Crypto.Generator {
) )
let decryptedData: Data? = cDecryptedDataPtr.map { Data(bytes: $0, count: outLen) } let decryptedData: Data? = cDecryptedDataPtr.map { Data(bytes: $0, count: outLen) }
cDecryptedDataPtr?.deallocate() free(UnsafeMutableRawPointer(mutating: cDecryptedDataPtr))
return try decryptedData ?? { throw MessageReceiverError.decryptionFailed }() return try decryptedData ?? { throw MessageReceiverError.decryptionFailed }()
} }

@ -119,12 +119,12 @@ internal extension LibSession {
let cSupplementData: UnsafeMutablePointer<UInt8> = cSupplementData let cSupplementData: UnsafeMutablePointer<UInt8> = cSupplementData
else { throw LibSessionError.failedToKeySupplementGroup } else { throw LibSessionError.failedToKeySupplementGroup }
// Must deallocate on success // Must free on success
let supplementData: Data = Data( let supplementData: Data = Data(
bytes: cSupplementData, bytes: cSupplementData,
count: cSupplementDataLen count: cSupplementDataLen
) )
cSupplementData.deallocate() free(UnsafeMutableRawPointer(mutating: cSupplementData))
return supplementData return supplementData
} }

@ -145,7 +145,7 @@ public extension LibSession {
count: cPushData.pointee.config_len count: cPushData.pointee.config_len
) )
let seqNo: Int64 = cPushData.pointee.seqno let seqNo: Int64 = cPushData.pointee.seqno
cPushData.deallocate() free(UnsafeMutableRawPointer(mutating: cPushData))
return PendingChanges.PushData( return PendingChanges.PushData(
data: pushData, data: pushData,
@ -201,7 +201,7 @@ public extension LibSession {
guard let dumpResult: UnsafeMutablePointer<UInt8> = dumpResult else { return nil } guard let dumpResult: UnsafeMutablePointer<UInt8> = dumpResult else { return nil }
let dumpData: Data = Data(bytes: dumpResult, count: dumpResultLen) let dumpData: Data = Data(bytes: dumpResult, count: dumpResultLen)
dumpResult.deallocate() free(UnsafeMutableRawPointer(mutating: dumpResult))
return dumpData return dumpData
} }
@ -219,7 +219,7 @@ public extension LibSession {
cStringArray: hashList.pointee.value, cStringArray: hashList.pointee.value,
count: hashList.pointee.len count: hashList.pointee.len
).defaulting(to: []) ).defaulting(to: [])
hashList.deallocate() free(UnsafeMutableRawPointer(mutating: hashList))
return result return result
@ -232,7 +232,7 @@ public extension LibSession {
cStringArray: hashList.pointee.value, cStringArray: hashList.pointee.value,
count: hashList.pointee.len count: hashList.pointee.len
).defaulting(to: []) ).defaulting(to: [])
hashList.deallocate() free(UnsafeMutableRawPointer(mutating: hashList))
return result return result
} }
@ -252,7 +252,7 @@ public extension LibSession {
cStringArray: hashList.pointee.value, cStringArray: hashList.pointee.value,
count: hashList.pointee.len count: hashList.pointee.len
).defaulting(to: []) ).defaulting(to: [])
hashList.deallocate() free(UnsafeMutableRawPointer(mutating: hashList))
return result return result
} }
@ -284,7 +284,7 @@ public extension LibSession {
.defaulting(to: []) .defaulting(to: [])
} }
.defaulting(to: []) .defaulting(to: [])
mergedHashesPtr?.deallocate() free(UnsafeMutableRawPointer(mutating: mergedHashesPtr))
if mergedHashes.count != messages.count { if mergedHashes.count != messages.count {
Log.warn(.libSession, "Unable to merge \(messages[0].namespace) messages (\(mergedHashes.count)/\(messages.count))") Log.warn(.libSession, "Unable to merge \(messages[0].namespace) messages (\(mergedHashes.count)/\(messages.count))")

@ -195,7 +195,7 @@ public extension Crypto.Generator {
let ciphertext: Data = maybeCiphertext.map({ Data(bytes: $0, count: ciphertextLen) }) let ciphertext: Data = maybeCiphertext.map({ Data(bytes: $0, count: ciphertextLen) })
else { throw MessageSenderError.encryptionFailed } else { throw MessageSenderError.encryptionFailed }
maybeCiphertext?.deallocate() free(UnsafeMutableRawPointer(mutating: maybeCiphertext))
return ciphertext return ciphertext
} }
@ -244,7 +244,7 @@ public extension Crypto.Generator {
let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) }) let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) })
else { throw MessageReceiverError.decryptionFailed } else { throw MessageReceiverError.decryptionFailed }
maybePlaintext?.deallocate() free(UnsafeMutableRawPointer(mutating: maybePlaintext))
return (plaintext, String(cString: cSenderSessionId)) return (plaintext, String(cString: cSenderSessionId))
} }

@ -177,7 +177,7 @@ fileprivate extension LibSessionUtilSpec {
expect(config_needs_dump(conf)).to(beTrue()) expect(config_needs_dump(conf)).to(beTrue())
expect { expect {
config_push(conf)?.deallocate() free(UnsafeMutableRawPointer(mutating: config_push(conf)))
try LibSessionError.throwIfNeeded(conf) try LibSessionError.throwIfNeeded(conf)
} }
.to(throwError(LibSessionError.libSessionError("Config data is too large."))) .to(throwError(LibSessionError.libSessionError("Config data is too large.")))
@ -292,7 +292,7 @@ fileprivate extension LibSessionUtilSpec {
let pushData1: UnsafeMutablePointer<config_push_data> = config_push(conf) let pushData1: UnsafeMutablePointer<config_push_data> = config_push(conf)
expect(pushData1.pointee.seqno).to(equal(0)) expect(pushData1.pointee.seqno).to(equal(0))
pushData1.deallocate() free(UnsafeMutableRawPointer(mutating: pushData1))
// Update the contact data // Update the contact data
contact2.set(\.name, to: "Joe") contact2.set(\.name, to: "Joe")
@ -341,7 +341,7 @@ fileprivate extension LibSessionUtilSpec {
config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash1) config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash1)
expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_push(conf)).to(beFalse())
expect(config_needs_dump(conf)).to(beTrue()) expect(config_needs_dump(conf)).to(beTrue())
pushData2.deallocate() free(UnsafeMutableRawPointer(mutating: pushData2))
// NB: Not going to check encrypted data and decryption here because that's general (not // NB: Not going to check encrypted data and decryption here because that's general (not
// specific to contacts) and is covered already in the user profile tests. // specific to contacts) and is covered already in the user profile tests.
@ -352,14 +352,14 @@ fileprivate extension LibSessionUtilSpec {
var error2: [CChar] = [CChar](repeating: 0, count: 256) var error2: [CChar] = [CChar](repeating: 0, count: 256)
var conf2: UnsafeMutablePointer<config_object>? = nil var conf2: UnsafeMutablePointer<config_object>? = nil
expect(contacts_init(&conf2, &userEdSK, dump1, dump1Len, &error2)).to(equal(0)) expect(contacts_init(&conf2, &userEdSK, dump1, dump1Len, &error2)).to(equal(0))
dump1?.deallocate() free(UnsafeMutableRawPointer(mutating: dump1))
expect(config_needs_push(conf2)).to(beFalse()) expect(config_needs_push(conf2)).to(beFalse())
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
let pushData3: UnsafeMutablePointer<config_push_data> = config_push(conf2) let pushData3: UnsafeMutablePointer<config_push_data> = config_push(conf2)
expect(pushData3.pointee.seqno).to(equal(1)) expect(pushData3.pointee.seqno).to(equal(1))
pushData3.deallocate() free(UnsafeMutableRawPointer(mutating: pushData3))
// Because we just called dump() above, to load up contacts2 // Because we just called dump() above, to load up contacts2
expect(config_needs_dump(conf)).to(beFalse()) expect(config_needs_dump(conf)).to(beFalse())
@ -398,22 +398,21 @@ fileprivate extension LibSessionUtilSpec {
// Check the merging // Check the merging
let fakeHash2: String = "fakehash2" let fakeHash2: String = "fakehash2"
var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)! var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)!
var mergeHashes: [UnsafePointer<CChar>?] = ((try? [cFakeHash2].unsafeCopyCStringArray()) ?? []) try? [fakeHash2].withUnsafeCStrArray { mergeHashes in
var mergeData: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData4.pointee.config)] var mergeData: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData4.pointee.config)]
var mergeSize: [Int] = [pushData4.pointee.config_len] var mergeSize: [Int] = [pushData4.pointee.config_len]
let mergedHashes: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes, &mergeData, &mergeSize, 1) let mergedHashes: UnsafeMutablePointer<config_string_list>? = config_merge(conf, mergeHashes.baseAddress, &mergeData, &mergeSize, 1)
expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len)) expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len))
.to(equal(["fakehash2"])) .to(equal(["fakehash2"]))
config_confirm_pushed(conf2, pushData4.pointee.seqno, &cFakeHash2) config_confirm_pushed(conf2, pushData4.pointee.seqno, &cFakeHash2)
mergeHashes.forEach { $0?.deallocate() } }
mergedHashes?.deallocate() free(UnsafeMutableRawPointer(mutating: pushData4))
pushData4.deallocate()
expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_push(conf)).to(beFalse())
let pushData5: UnsafeMutablePointer<config_push_data> = config_push(conf) let pushData5: UnsafeMutablePointer<config_push_data> = config_push(conf)
expect(pushData5.pointee.seqno).to(equal(2)) expect(pushData5.pointee.seqno).to(equal(2))
pushData5.deallocate() free(UnsafeMutableRawPointer(mutating: pushData5))
// Iterate through and make sure we got everything we expected // Iterate through and make sure we got everything we expected
var sessionIds: [String] = [] var sessionIds: [String] = []
@ -477,27 +476,25 @@ fileprivate extension LibSessionUtilSpec {
config_confirm_pushed(conf, pushData6.pointee.seqno, &cFakeHash3a) config_confirm_pushed(conf, pushData6.pointee.seqno, &cFakeHash3a)
config_confirm_pushed(conf2, pushData7.pointee.seqno, &cFakeHash3b) config_confirm_pushed(conf2, pushData7.pointee.seqno, &cFakeHash3b)
var mergeHashes2: [UnsafePointer<CChar>?] = ((try? [cFakeHash3b].unsafeCopyCStringArray()) ?? []) try? [fakeHash3b].withUnsafeCStrArray { mergeHashes2 in
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData7.pointee.config)] var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData7.pointee.config)]
var mergeSize2: [Int] = [pushData7.pointee.config_len] var mergeSize2: [Int] = [pushData7.pointee.config_len]
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1) let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1)
expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash3b"])) .to(equal(["fakehash3b"]))
}
expect(config_needs_push(conf)).to(beTrue()) expect(config_needs_push(conf)).to(beTrue())
mergeHashes2.forEach { $0?.deallocate() } free(UnsafeMutableRawPointer(mutating: pushData7))
mergedHashes2?.deallocate()
pushData7.deallocate() try? [fakeHash3a].withUnsafeCStrArray { mergeHashes3 in
var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData6.pointee.config)]
var mergeHashes3: [UnsafePointer<CChar>?] = ((try? [cFakeHash3a].unsafeCopyCStringArray()) ?? []) var mergeSize3: [Int] = [pushData6.pointee.config_len]
var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData6.pointee.config)] let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 1)
var mergeSize3: [Int] = [pushData6.pointee.config_len] expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1) .to(equal(["fakehash3a"]))
expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) }
.to(equal(["fakehash3a"]))
expect(config_needs_push(conf2)).to(beTrue()) expect(config_needs_push(conf2)).to(beTrue())
mergeHashes3.forEach { $0?.deallocate() } free(UnsafeMutableRawPointer(mutating: pushData6))
mergedHashes3?.deallocate()
pushData6.deallocate()
let pushData8: UnsafeMutablePointer<config_push_data> = config_push(conf) let pushData8: UnsafeMutablePointer<config_push_data> = config_push(conf)
expect(pushData8.pointee.seqno).to(equal(4)) expect(pushData8.pointee.seqno).to(equal(4))
@ -517,8 +514,8 @@ fileprivate extension LibSessionUtilSpec {
var cFakeHash4: [CChar] = fakeHash4.cString(using: .utf8)! var cFakeHash4: [CChar] = fakeHash4.cString(using: .utf8)!
config_confirm_pushed(conf, pushData8.pointee.seqno, &cFakeHash4) config_confirm_pushed(conf, pushData8.pointee.seqno, &cFakeHash4)
config_confirm_pushed(conf2, pushData9.pointee.seqno, &cFakeHash4) config_confirm_pushed(conf2, pushData9.pointee.seqno, &cFakeHash4)
pushData8.deallocate() free(UnsafeMutableRawPointer(mutating: pushData8))
pushData9.deallocate() free(UnsafeMutableRawPointer(mutating: pushData9))
expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_push(conf)).to(beFalse())
expect(config_needs_push(conf2)).to(beFalse()) expect(config_needs_push(conf2)).to(beFalse())
@ -680,13 +677,13 @@ fileprivate extension LibSessionUtilSpec {
// (in a real client we'd now store this to disk) // (in a real client we'd now store this to disk)
expect(config_needs_dump(conf)).to(beFalse()) expect(config_needs_dump(conf)).to(beFalse())
dump1?.deallocate() free(UnsafeMutableRawPointer(mutating: dump1))
// So now imagine we got back confirmation from the swarm that the push has been stored: // So now imagine we got back confirmation from the swarm that the push has been stored:
let fakeHash1: String = "fakehash1" let fakeHash1: String = "fakehash1"
var cFakeHash1: [CChar] = fakeHash1.cString(using: .utf8)! var cFakeHash1: [CChar] = fakeHash1.cString(using: .utf8)!
config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash1) config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash1)
pushData2.deallocate() free(UnsafeMutableRawPointer(mutating: pushData2))
expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_push(conf)).to(beFalse())
expect(config_needs_dump(conf)).to(beTrue()) // The confirmation changes state, so this makes us need a dump expect(config_needs_dump(conf)).to(beTrue()) // The confirmation changes state, so this makes us need a dump
@ -694,7 +691,7 @@ fileprivate extension LibSessionUtilSpec {
var dump2: UnsafeMutablePointer<UInt8>? = nil var dump2: UnsafeMutablePointer<UInt8>? = nil
var dump2Len: Int = 0 var dump2Len: Int = 0
config_dump(conf, &dump2, &dump2Len) config_dump(conf, &dump2, &dump2Len)
dump2?.deallocate() free(UnsafeMutableRawPointer(mutating: dump2))
expect(config_needs_dump(conf)).to(beFalse()) expect(config_needs_dump(conf)).to(beFalse())
// Now we're going to set up a second, competing config object (in the real world this would be // Now we're going to set up a second, competing config object (in the real world this would be
@ -708,15 +705,14 @@ fileprivate extension LibSessionUtilSpec {
// Now imagine we just pulled down the `exp_push1` string from the swarm; we merge it into // Now imagine we just pulled down the `exp_push1` string from the swarm; we merge it into
// conf2: // conf2:
var mergeHashes: [UnsafePointer<CChar>?] = ((try? [cFakeHash1].unsafeCopyCStringArray()) ?? []) try? [fakeHash1].withUnsafeCStrArray { mergeHashes in
var mergeData: [UnsafePointer<UInt8>?] = ((try? [expPush1Encrypted].unsafeCopyUInt8Array()) ?? []) try? [expPush1Encrypted].withUnsafeUInt8CArray { mergeData in
var mergeSize: [Int] = [expPush1Encrypted.count] var mergeSize: [Int] = [expPush1Encrypted.count]
let mergedHashes: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes, &mergeData, &mergeSize, 1) let mergedHashes: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, mergeHashes.baseAddress, mergeData.baseAddress, &mergeSize, 1)
expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len)) expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len))
.to(equal(["fakehash1"])) .to(equal(["fakehash1"]))
mergeHashes.forEach { $0?.deallocate() } }
mergeData.forEach { $0?.deallocate() } }
mergedHashes?.deallocate()
// Our state has changed, so we need to dump: // Our state has changed, so we need to dump:
expect(config_needs_dump(conf2)).to(beTrue()) expect(config_needs_dump(conf2)).to(beTrue())
@ -724,7 +720,7 @@ fileprivate extension LibSessionUtilSpec {
var dump3Len: Int = 0 var dump3Len: Int = 0
config_dump(conf2, &dump3, &dump3Len) config_dump(conf2, &dump3, &dump3Len)
// (store in db) // (store in db)
dump3?.deallocate() free(UnsafeMutableRawPointer(mutating: dump3))
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
// We *don't* need to push: even though we updated, all we did is update to the merged data (and // We *don't* need to push: even though we updated, all we did is update to the merged data (and
@ -777,8 +773,8 @@ fileprivate extension LibSessionUtilSpec {
var dump5Len: Int = 0 var dump5Len: Int = 0
config_dump(conf2, &dump5, &dump5Len); config_dump(conf2, &dump5, &dump5Len);
// (store in db) // (store in db)
dump4?.deallocate() free(UnsafeMutableRawPointer(mutating: dump4))
dump5?.deallocate() free(UnsafeMutableRawPointer(mutating: dump5))
// Since we set different things, we're going to get back different serialized data to be // Since we set different things, we're going to get back different serialized data to be
// pushed: // pushed:
@ -791,25 +787,23 @@ fileprivate extension LibSessionUtilSpec {
// Feed the new config into each other. (This array could hold multiple configs if we pulled // Feed the new config into each other. (This array could hold multiple configs if we pulled
// down more than one). // down more than one).
var mergeHashes2: [UnsafePointer<CChar>?] = ((try? [cFakeHash2].unsafeCopyCStringArray()) ?? []) try? [fakeHash2].withUnsafeCStrArray { mergeHashes2 in
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData3.pointee.config)] var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData3.pointee.config)]
var mergeSize2: [Int] = [pushData3.pointee.config_len] var mergeSize2: [Int] = [pushData3.pointee.config_len]
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes2, &mergeData2, &mergeSize2, 1) let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1)
expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash2"])) .to(equal(["fakehash2"]))
mergeHashes2.forEach { $0?.deallocate() } }
mergedHashes2?.deallocate() free(UnsafeMutableRawPointer(mutating: pushData3))
pushData3.deallocate()
try? [fakeHash3].withUnsafeCStrArray { mergeHashes3 in
var mergeHashes3: [UnsafePointer<CChar>?] = ((try? [cFakeHash3].unsafeCopyCStringArray()) ?? []) var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData4.pointee.config)]
var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData4.pointee.config)] var mergeSize3: [Int] = [pushData4.pointee.config_len]
var mergeSize3: [Int] = [pushData4.pointee.config_len] let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 1)
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes3, &mergeData3, &mergeSize3, 1) expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) .to(equal(["fakehash3"]))
.to(equal(["fakehash3"])) }
mergeHashes3.forEach { $0?.deallocate() } free(UnsafeMutableRawPointer(mutating: pushData4))
mergedHashes3?.deallocate()
pushData4.deallocate()
// Now after the merge we *will* want to push from both client, since both will have generated a // Now after the merge we *will* want to push from both client, since both will have generated a
// merge conflict update (with seqno = 3). // merge conflict update (with seqno = 3).
@ -849,8 +843,8 @@ fileprivate extension LibSessionUtilSpec {
var cFakeHash5: [CChar] = fakeHash5.cString(using: .utf8)! var cFakeHash5: [CChar] = fakeHash5.cString(using: .utf8)!
config_confirm_pushed(conf, pushData5.pointee.seqno, &cFakeHash4) config_confirm_pushed(conf, pushData5.pointee.seqno, &cFakeHash4)
config_confirm_pushed(conf2, pushData6.pointee.seqno, &cFakeHash5) config_confirm_pushed(conf2, pushData6.pointee.seqno, &cFakeHash5)
pushData5.deallocate() free(UnsafeMutableRawPointer(mutating: pushData5))
pushData6.deallocate() free(UnsafeMutableRawPointer(mutating: pushData6))
var dump6: UnsafeMutablePointer<UInt8>? = nil var dump6: UnsafeMutablePointer<UInt8>? = nil
var dump6Len: Int = 0 var dump6Len: Int = 0
@ -859,8 +853,8 @@ fileprivate extension LibSessionUtilSpec {
var dump7Len: Int = 0 var dump7Len: Int = 0
config_dump(conf2, &dump7, &dump7Len); config_dump(conf2, &dump7, &dump7Len);
// (store in db) // (store in db)
dump6?.deallocate() free(UnsafeMutableRawPointer(mutating: dump6))
dump7?.deallocate() free(UnsafeMutableRawPointer(mutating: dump7))
expect(config_needs_dump(conf)).to(beFalse()) expect(config_needs_dump(conf)).to(beFalse())
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
@ -869,8 +863,8 @@ fileprivate extension LibSessionUtilSpec {
// Wouldn't do this in a normal session but doing it here to properly clean up // Wouldn't do this in a normal session but doing it here to properly clean up
// after the test // after the test
conf?.deallocate() free(UnsafeMutableRawPointer(mutating: conf))
conf2?.deallocate() free(UnsafeMutableRawPointer(mutating: conf2))
} }
} }
} }
@ -968,7 +962,7 @@ fileprivate extension LibSessionUtilSpec {
config_confirm_pushed(conf, pushData1.pointee.seqno, &cFakeHash1) config_confirm_pushed(conf, pushData1.pointee.seqno, &cFakeHash1)
expect(config_needs_dump(conf)).to(beTrue()) expect(config_needs_dump(conf)).to(beTrue())
expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_push(conf)).to(beFalse())
pushData1.deallocate() free(UnsafeMutableRawPointer(mutating: pushData1))
var dump1: UnsafeMutablePointer<UInt8>? = nil var dump1: UnsafeMutablePointer<UInt8>? = nil
var dump1Len: Int = 0 var dump1Len: Int = 0
@ -977,7 +971,7 @@ fileprivate extension LibSessionUtilSpec {
var error2: [CChar] = [CChar](repeating: 0, count: 256) var error2: [CChar] = [CChar](repeating: 0, count: 256)
var conf2: UnsafeMutablePointer<config_object>? = nil var conf2: UnsafeMutablePointer<config_object>? = nil
expect(convo_info_volatile_init(&conf2, &userEdSK, dump1, dump1Len, &error2)).to(equal(0)) expect(convo_info_volatile_init(&conf2, &userEdSK, dump1, dump1Len, &error2)).to(equal(0))
dump1?.deallocate() free(UnsafeMutableRawPointer(mutating: dump1))
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
expect(config_needs_push(conf2)).to(beFalse()) expect(config_needs_push(conf2)).to(beFalse())
@ -1017,16 +1011,15 @@ fileprivate extension LibSessionUtilSpec {
// Check the merging // Check the merging
let fakeHash2: String = "fakehash2" let fakeHash2: String = "fakehash2"
var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)! var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)!
var mergeHashes: [UnsafePointer<CChar>?] = ((try? [cFakeHash2].unsafeCopyCStringArray()) ?? []) try? [fakeHash2].withUnsafeCStrArray { mergeHashes in
var mergeData: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData2.pointee.config)] var mergeData: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData2.pointee.config)]
var mergeSize: [Int] = [pushData2.pointee.config_len] var mergeSize: [Int] = [pushData2.pointee.config_len]
let mergedHashes: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes, &mergeData, &mergeSize, 1) let mergedHashes: UnsafeMutablePointer<config_string_list>? = config_merge(conf, mergeHashes.baseAddress, &mergeData, &mergeSize, 1)
expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len)) expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len))
.to(equal(["fakehash2"])) .to(equal(["fakehash2"]))
config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash2) config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash2)
mergeHashes.forEach { $0?.deallocate() } }
mergedHashes?.deallocate() free(UnsafeMutableRawPointer(mutating: pushData2))
pushData2.deallocate()
expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_push(conf)).to(beFalse())
@ -1191,7 +1184,7 @@ fileprivate extension LibSessionUtilSpec {
expect([String](cStringArray: pushData1.pointee.obsolete, count: pushData1.pointee.obsolete_len)) expect([String](cStringArray: pushData1.pointee.obsolete, count: pushData1.pointee.obsolete_len))
.to(beEmpty()) .to(beEmpty())
expect(pushData1.pointee.config_len).to(equal(432)) expect(pushData1.pointee.config_len).to(equal(432))
pushData1.deallocate() free(UnsafeMutableRawPointer(mutating: pushData1))
let users: [String] = [ let users: [String] = [
"050000000000000000000000000000000000000000000000000000000000000000", "050000000000000000000000000000000000000000000000000000000000000000",
@ -1303,7 +1296,7 @@ fileprivate extension LibSessionUtilSpec {
var error2: [CChar] = [CChar](repeating: 0, count: 256) var error2: [CChar] = [CChar](repeating: 0, count: 256)
var conf2: UnsafeMutablePointer<config_object>? = nil var conf2: UnsafeMutablePointer<config_object>? = nil
expect(user_groups_init(&conf2, &userEdSK, dump1, dump1Len, &error2)).to(equal(0)) expect(user_groups_init(&conf2, &userEdSK, dump1, dump1Len, &error2)).to(equal(0))
dump1?.deallocate() free(UnsafeMutableRawPointer(mutating: dump1))
expect(config_needs_dump(conf)).to(beFalse()) // Because we just called dump() above, to load up conf2 expect(config_needs_dump(conf)).to(beFalse()) // Because we just called dump() above, to load up conf2
expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_push(conf)).to(beFalse())
@ -1312,12 +1305,12 @@ fileprivate extension LibSessionUtilSpec {
expect(pushData3.pointee.seqno).to(equal(1)) expect(pushData3.pointee.seqno).to(equal(1))
expect([String](cStringArray: pushData3.pointee.obsolete, count: pushData3.pointee.obsolete_len)) expect([String](cStringArray: pushData3.pointee.obsolete, count: pushData3.pointee.obsolete_len))
.to(beEmpty()) .to(beEmpty())
pushData3.deallocate() free(UnsafeMutableRawPointer(mutating: pushData3))
let currentHashes1: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf) let currentHashes1: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf)
expect([String](cStringArray: currentHashes1?.pointee.value, count: currentHashes1?.pointee.len)) expect([String](cStringArray: currentHashes1?.pointee.value, count: currentHashes1?.pointee.len))
.to(equal(["fakehash1"])) .to(equal(["fakehash1"]))
currentHashes1?.deallocate() free(UnsafeMutableRawPointer(mutating: currentHashes1))
expect(config_needs_push(conf2)).to(beFalse()) expect(config_needs_push(conf2)).to(beFalse())
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
@ -1327,12 +1320,12 @@ fileprivate extension LibSessionUtilSpec {
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
expect([String](cStringArray: pushData4.pointee.obsolete, count: pushData4.pointee.obsolete_len)) expect([String](cStringArray: pushData4.pointee.obsolete, count: pushData4.pointee.obsolete_len))
.to(beEmpty()) .to(beEmpty())
pushData4.deallocate() free(UnsafeMutableRawPointer(mutating: pushData4))
let currentHashes2: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2) let currentHashes2: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2)
expect([String](cStringArray: currentHashes2?.pointee.value, count: currentHashes2?.pointee.len)) expect([String](cStringArray: currentHashes2?.pointee.value, count: currentHashes2?.pointee.len))
.to(equal(["fakehash1"])) .to(equal(["fakehash1"]))
currentHashes2?.deallocate() free(UnsafeMutableRawPointer(mutating: currentHashes2))
expect(user_groups_size(conf2)).to(equal(2)) expect(user_groups_size(conf2)).to(equal(2))
expect(user_groups_size_communities(conf2)).to(equal(1)) expect(user_groups_size_communities(conf2)).to(equal(1))
@ -1375,7 +1368,7 @@ fileprivate extension LibSessionUtilSpec {
let pushData5: UnsafeMutablePointer<config_push_data> = config_push(conf2) let pushData5: UnsafeMutablePointer<config_push_data> = config_push(conf2)
expect(pushData5.pointee.seqno).to(equal(1)) expect(pushData5.pointee.seqno).to(equal(1))
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
pushData5.deallocate() free(UnsafeMutableRawPointer(mutating: pushData5))
for targetConf in [conf, conf2] { for targetConf in [conf, conf2] {
// Iterate through and make sure we got everything we expected // Iterate through and make sure we got everything we expected
@ -1427,7 +1420,7 @@ fileprivate extension LibSessionUtilSpec {
let pushData6: UnsafeMutablePointer<config_push_data> = config_push(conf2) let pushData6: UnsafeMutablePointer<config_push_data> = config_push(conf2)
expect(pushData6.pointee.seqno).to(equal(1)) expect(pushData6.pointee.seqno).to(equal(1))
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
pushData6.deallocate() free(UnsafeMutableRawPointer(mutating: pushData6))
community2.set(\.room, to: "sudokuRoom") // Change capitalization community2.set(\.room, to: "sudokuRoom") // Change capitalization
user_groups_set_community(conf2, &community2) user_groups_set_community(conf2, &community2)
@ -1446,7 +1439,7 @@ fileprivate extension LibSessionUtilSpec {
let currentHashes3: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2) let currentHashes3: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2)
expect([String](cStringArray: currentHashes3?.pointee.value, count: currentHashes3?.pointee.len)) expect([String](cStringArray: currentHashes3?.pointee.value, count: currentHashes3?.pointee.len))
.to(equal([fakeHash2])) .to(equal([fakeHash2]))
currentHashes3?.deallocate() free(UnsafeMutableRawPointer(mutating: currentHashes3))
var dump2: UnsafeMutablePointer<UInt8>? = nil var dump2: UnsafeMutablePointer<UInt8>? = nil
var dump2Len: Int = 0 var dump2Len: Int = 0
@ -1460,15 +1453,14 @@ fileprivate extension LibSessionUtilSpec {
config_confirm_pushed(conf2, pushData8.pointee.seqno, &cFakeHash2) config_confirm_pushed(conf2, pushData8.pointee.seqno, &cFakeHash2)
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
var mergeHashes1: [UnsafePointer<CChar>?] = ((try? [cFakeHash2].unsafeCopyCStringArray()) ?? []) try? [fakeHash2].withUnsafeCStrArray { mergeHashes1 in
var mergeData1: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData8.pointee.config)] var mergeData1: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData8.pointee.config)]
var mergeSize1: [Int] = [pushData8.pointee.config_len] var mergeSize1: [Int] = [pushData8.pointee.config_len]
let mergedHashes1: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes1, &mergeData1, &mergeSize1, 1) let mergedHashes1: UnsafeMutablePointer<config_string_list>? = config_merge(conf, mergeHashes1.baseAddress, &mergeData1, &mergeSize1, 1)
expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len)) expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len))
.to(equal(["fakehash2"])) .to(equal(["fakehash2"]))
mergeHashes1.forEach { $0?.deallocate() } }
mergedHashes1?.deallocate() free(UnsafeMutableRawPointer(mutating: pushData8))
pushData8.deallocate()
var cCommunity3BaseUrl: [CChar] = "http://example.org:5678".cString(using: .utf8)! var cCommunity3BaseUrl: [CChar] = "http://example.org:5678".cString(using: .utf8)!
var cCommunity3Room: [CChar] = "SudokuRoom".cString(using: .utf8)! var cCommunity3Room: [CChar] = "SudokuRoom".cString(using: .utf8)!
@ -1493,7 +1485,7 @@ fileprivate extension LibSessionUtilSpec {
let pushData9: UnsafeMutablePointer<config_push_data> = config_push(conf2) let pushData9: UnsafeMutablePointer<config_push_data> = config_push(conf2)
expect(pushData9.pointee.seqno).to(equal(2)) expect(pushData9.pointee.seqno).to(equal(2))
expect(config_needs_dump(conf2)).to(beFalse()) expect(config_needs_dump(conf2)).to(beFalse())
pushData9.deallocate() free(UnsafeMutableRawPointer(mutating: pushData9))
user_groups_set_free_legacy_group(conf2, legacyGroup5) user_groups_set_free_legacy_group(conf2, legacyGroup5)
expect(config_needs_push(conf2)).to(beTrue()) expect(config_needs_push(conf2)).to(beTrue())
@ -1515,16 +1507,15 @@ fileprivate extension LibSessionUtilSpec {
let currentHashes4: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2) let currentHashes4: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2)
expect([String](cStringArray: currentHashes4?.pointee.value, count: currentHashes4?.pointee.len)) expect([String](cStringArray: currentHashes4?.pointee.value, count: currentHashes4?.pointee.len))
.to(equal([fakeHash3])) .to(equal([fakeHash3]))
currentHashes4?.deallocate() free(UnsafeMutableRawPointer(mutating: currentHashes4))
var mergeHashes2: [UnsafePointer<CChar>?] = ((try? [cFakeHash3].unsafeCopyCStringArray()) ?? []) try? [fakeHash3].withUnsafeCStrArray { mergeHashes2 in
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData10.pointee.config)] var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData10.pointee.config)]
var mergeSize2: [Int] = [pushData10.pointee.config_len] var mergeSize2: [Int] = [pushData10.pointee.config_len]
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1) let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1)
expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash3"])) .to(equal(["fakehash3"]))
mergeHashes2.forEach { $0?.deallocate() } }
mergedHashes2?.deallocate()
expect(user_groups_size(conf)).to(equal(1)) expect(user_groups_size(conf)).to(equal(1))
expect(user_groups_size_communities(conf)).to(equal(0)) expect(user_groups_size_communities(conf)).to(equal(0))
@ -1566,41 +1557,40 @@ fileprivate extension LibSessionUtilSpec {
let cFakeHash11: [CChar] = fakeHash11.cString(using: .utf8)! let cFakeHash11: [CChar] = fakeHash11.cString(using: .utf8)!
let fakeHash12: String = "fakehash12" let fakeHash12: String = "fakehash12"
let cFakeHash12: [CChar] = fakeHash12.cString(using: .utf8)! let cFakeHash12: [CChar] = fakeHash12.cString(using: .utf8)!
var mergeHashes3: [UnsafePointer<CChar>?] = ((try? [cFakeHash10, cFakeHash11, cFakeHash12, cFakeHash4].unsafeCopyCStringArray()) ?? []) try? [fakeHash10, fakeHash11, fakeHash12, fakeHash4].withUnsafeCStrArray { mergeHashes3 in
var mergeData3: [UnsafePointer<UInt8>?] = [ var mergeData3: [UnsafePointer<UInt8>?] = [
UnsafePointer(pushData10.pointee.config), UnsafePointer(pushData10.pointee.config),
UnsafePointer(pushData2.pointee.config), UnsafePointer(pushData2.pointee.config),
UnsafePointer(pushData7.pointee.config), UnsafePointer(pushData7.pointee.config),
UnsafePointer(pushData11.pointee.config) UnsafePointer(pushData11.pointee.config)
] ]
var mergeSize3: [Int] = [ var mergeSize3: [Int] = [
pushData10.pointee.config_len, pushData10.pointee.config_len,
pushData2.pointee.config_len, pushData2.pointee.config_len,
pushData7.pointee.config_len, pushData7.pointee.config_len,
pushData11.pointee.config_len pushData11.pointee.config_len
] ]
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 4) let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 4)
expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
.to(equal(["fakehash10", "fakehash11", "fakehash12", "fakehash4"])) .to(equal(["fakehash10", "fakehash11", "fakehash12", "fakehash4"]))
expect(config_needs_dump(conf2)).to(beTrue()) expect(config_needs_dump(conf2)).to(beTrue())
expect(config_needs_push(conf2)).to(beFalse()) expect(config_needs_push(conf2)).to(beFalse())
mergeHashes3.forEach { $0?.deallocate() } }
mergedHashes3?.deallocate() free(UnsafeMutableRawPointer(mutating: pushData2))
pushData2.deallocate() free(UnsafeMutableRawPointer(mutating: pushData7))
pushData7.deallocate() free(UnsafeMutableRawPointer(mutating: pushData10))
pushData10.deallocate() free(UnsafeMutableRawPointer(mutating: pushData11))
pushData11.deallocate()
let currentHashes5: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2) let currentHashes5: UnsafeMutablePointer<config_string_list>? = config_current_hashes(conf2)
expect([String](cStringArray: currentHashes5?.pointee.value, count: currentHashes5?.pointee.len)) expect([String](cStringArray: currentHashes5?.pointee.value, count: currentHashes5?.pointee.len))
.to(equal([fakeHash4])) .to(equal([fakeHash4]))
currentHashes5?.deallocate() free(UnsafeMutableRawPointer(mutating: currentHashes5))
let pushData12: UnsafeMutablePointer<config_push_data> = config_push(conf2) let pushData12: UnsafeMutablePointer<config_push_data> = config_push(conf2)
expect(pushData12.pointee.seqno).to(equal(4)) expect(pushData12.pointee.seqno).to(equal(4))
expect([String](cStringArray: pushData12.pointee.obsolete, count: pushData12.pointee.obsolete_len)) expect([String](cStringArray: pushData12.pointee.obsolete, count: pushData12.pointee.obsolete_len))
.to(equal([fakeHash11, fakeHash12, fakeHash10, fakeHash3])) .to(equal([fakeHash11, fakeHash12, fakeHash10, fakeHash3]))
pushData12.deallocate() free(UnsafeMutableRawPointer(mutating: pushData12))
for targetConf in [conf, conf2] { for targetConf in [conf, conf2] {
// Iterate through and make sure we got everything we expected // Iterate through and make sure we got everything we expected
@ -1712,16 +1702,15 @@ fileprivate extension LibSessionUtilSpec {
expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_push(conf)).to(beFalse())
expect(config_needs_dump(conf)).to(beTrue()) expect(config_needs_dump(conf)).to(beTrue())
var mergeHashes1: [UnsafePointer<CChar>?] = try! [cFakeHash1].unsafeCopyCStringArray() try? [fakeHash1].withUnsafeCStrArray { mergeHashes1 in
var mergeData1: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData1.pointee.config)] var mergeData1: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData1.pointee.config)]
var mergeSize1: [Int] = [pushData1.pointee.config_len] var mergeSize1: [Int] = [pushData1.pointee.config_len]
let mergedHashes1: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes1, &mergeData1, &mergeSize1, 1) let mergedHashes1: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, mergeHashes1.baseAddress, &mergeData1, &mergeSize1, 1)
expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len)) expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len))
.to(equal(["fakehash1"])) .to(equal(["fakehash1"]))
expect(config_needs_push(conf2)).to(beFalse()) expect(config_needs_push(conf2)).to(beFalse())
mergeHashes1.forEach { $0?.deallocate() } }
mergedHashes1?.deallocate() free(UnsafeMutableRawPointer(mutating: pushData1))
pushData1.deallocate()
let namePtr: UnsafePointer<CChar>? = groups_info_get_name(conf2) let namePtr: UnsafePointer<CChar>? = groups_info_get_name(conf2)
let descPtr: UnsafePointer<CChar>? = groups_info_get_description(conf2) let descPtr: UnsafePointer<CChar>? = groups_info_get_description(conf2)
@ -1757,14 +1746,13 @@ fileprivate extension LibSessionUtilSpec {
var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)! var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)!
config_confirm_pushed(conf2, pushData2.pointee.seqno, &cFakeHash2) config_confirm_pushed(conf2, pushData2.pointee.seqno, &cFakeHash2)
var mergeHashes2: [UnsafePointer<CChar>?] = try! [cFakeHash2].unsafeCopyCStringArray() try? [fakeHash2].withUnsafeCStrArray { mergeHashes2 in
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData2.pointee.config)] var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData2.pointee.config)]
var mergeSize2: [Int] = [pushData2.pointee.config_len] var mergeSize2: [Int] = [pushData2.pointee.config_len]
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1) let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1)
expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash2"])) .to(equal(["fakehash2"]))
mergeHashes2.forEach { $0?.deallocate() } }
mergedHashes2?.deallocate()
expect(groups_info_set_name(conf, "Better name!")).to(equal(0)) expect(groups_info_set_name(conf, "Better name!")).to(equal(0))
expect(groups_info_set_description(conf, "Test New Name Really long abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz")).to(equal(0)) expect(groups_info_set_description(conf, "Test New Name Really long abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz")).to(equal(0))
@ -1795,15 +1783,14 @@ fileprivate extension LibSessionUtilSpec {
var cFakeHash3: [CChar] = fakeHash3.cString(using: .utf8)! var cFakeHash3: [CChar] = fakeHash3.cString(using: .utf8)!
config_confirm_pushed(conf, pushData3.pointee.seqno, &cFakeHash3) config_confirm_pushed(conf, pushData3.pointee.seqno, &cFakeHash3)
var mergeHashes3: [UnsafePointer<CChar>?] = try! [cFakeHash3].unsafeCopyCStringArray() try? [fakeHash3].withUnsafeCStrArray { mergeHashes3 in
var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData3.pointee.config)] var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData3.pointee.config)]
var mergeSize3: [Int] = [pushData3.pointee.config_len] var mergeSize3: [Int] = [pushData3.pointee.config_len]
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1) let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 1)
expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
.to(equal(["fakehash3"])) .to(equal(["fakehash3"]))
mergeHashes3.forEach { $0?.deallocate() } }
mergedHashes3?.deallocate() free(UnsafeMutableRawPointer(mutating: pushData3))
pushData3.deallocate()
let namePtr3: UnsafePointer<CChar>? = groups_info_get_name(conf2) let namePtr3: UnsafePointer<CChar>? = groups_info_get_name(conf2)
let descPtr3: UnsafePointer<CChar>? = groups_info_get_description(conf2) let descPtr3: UnsafePointer<CChar>? = groups_info_get_description(conf2)
@ -2064,16 +2051,15 @@ fileprivate extension LibSessionUtilSpec {
expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_push(conf)).to(beFalse())
expect(config_needs_dump(conf)).to(beTrue()) expect(config_needs_dump(conf)).to(beTrue())
var mergeHashes1: [UnsafePointer<CChar>?] = try! [cFakeHash1].unsafeCopyCStringArray() try? [fakeHash1].withUnsafeCStrArray { mergeHashes1 in
var mergeData1: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData1.pointee.config)] var mergeData1: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData1.pointee.config)]
var mergeSize1: [Int] = [pushData1.pointee.config_len] var mergeSize1: [Int] = [pushData1.pointee.config_len]
let mergedHashes1: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes1, &mergeData1, &mergeSize1, 1) let mergedHashes1: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, mergeHashes1.baseAddress, &mergeData1, &mergeSize1, 1)
expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len)) expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len))
.to(equal(["fakehash1"])) .to(equal(["fakehash1"]))
expect(config_needs_push(conf2)).to(beFalse()) expect(config_needs_push(conf2)).to(beFalse())
mergeHashes1.forEach { $0?.deallocate() } }
mergedHashes1?.deallocate() free(UnsafeMutableRawPointer(mutating: pushData1))
pushData1.deallocate()
expect(groups_members_size(conf2)).to(equal(25)) expect(groups_members_size(conf2)).to(equal(25))
@ -2171,14 +2157,13 @@ fileprivate extension LibSessionUtilSpec {
var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)! var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)!
config_confirm_pushed(conf2, pushData2.pointee.seqno, &cFakeHash2) config_confirm_pushed(conf2, pushData2.pointee.seqno, &cFakeHash2)
var mergeHashes2: [UnsafePointer<CChar>?] = try! [cFakeHash2].unsafeCopyCStringArray() try? [fakeHash2].withUnsafeCStrArray { mergeHashes2 in
var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData2.pointee.config)] var mergeData2: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData2.pointee.config)]
var mergeSize2: [Int] = [pushData2.pointee.config_len] var mergeSize2: [Int] = [pushData2.pointee.config_len]
let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1) let mergedHashes2: UnsafeMutablePointer<config_string_list>? = config_merge(conf, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1)
expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len))
.to(equal(["fakehash2"])) .to(equal(["fakehash2"]))
mergeHashes2.forEach { $0?.deallocate() } }
mergedHashes2?.deallocate()
var cSessionId2: [CChar] = sids[23].cString(using: .utf8)! var cSessionId2: [CChar] = sids[23].cString(using: .utf8)!
var member2: config_group_member = config_group_member() var member2: config_group_member = config_group_member()
@ -2344,14 +2329,13 @@ fileprivate extension LibSessionUtilSpec {
var cFakeHash3: [CChar] = fakeHash3.cString(using: .utf8)! var cFakeHash3: [CChar] = fakeHash3.cString(using: .utf8)!
config_confirm_pushed(conf, pushData3.pointee.seqno, &cFakeHash3) config_confirm_pushed(conf, pushData3.pointee.seqno, &cFakeHash3)
var mergeHashes3: [UnsafePointer<CChar>?] = try! [cFakeHash3].unsafeCopyCStringArray() try? [fakeHash3].withUnsafeCStrArray { mergeHashes3 in
var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData3.pointee.config)] var mergeData3: [UnsafePointer<UInt8>?] = [UnsafePointer(pushData3.pointee.config)]
var mergeSize3: [Int] = [pushData3.pointee.config_len] var mergeSize3: [Int] = [pushData3.pointee.config_len]
let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1) let mergedHashes3: UnsafeMutablePointer<config_string_list>? = config_merge(conf2, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 1)
expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len))
.to(equal(["fakehash3"])) .to(equal(["fakehash3"]))
mergeHashes3.forEach { $0?.deallocate() } }
mergedHashes3?.deallocate()
expect(groups_members_size(conf2)).to(equal(48)) // 18 deleted earlier expect(groups_members_size(conf2)).to(equal(48)) // 18 deleted earlier
@ -2539,7 +2523,7 @@ fileprivate extension LibSessionUtilSpec {
groups_keys_dump(keysConf, &dumpResult, &dumpResultLen) groups_keys_dump(keysConf, &dumpResult, &dumpResultLen)
let dumpData: Data = Data(bytes: dumpResult!, count: dumpResultLen) let dumpData: Data = Data(bytes: dumpResult!, count: dumpResultLen)
dumpResult?.deallocate() free(UnsafeMutableRawPointer(mutating: dumpResult))
return dumpData.toHexString() return dumpData.toHexString()
} }
@ -2665,7 +2649,7 @@ private extension LibSessionUtilSpec {
guard let result: UnsafeMutablePointer<config_push_data> = config_push(conf) else { return true } guard let result: UnsafeMutablePointer<config_push_data> = config_push(conf) else { return true }
// We successfully generated the config push and didn't hit the limit // We successfully generated the config push and didn't hit the limit
result.deallocate() free(UnsafeMutableRawPointer(mutating: result))
case 50...100: case 50...100:
// Between 50 and 100 records of the expected limit only check every `10` records // Between 50 and 100 records of the expected limit only check every `10` records
@ -2673,7 +2657,7 @@ private extension LibSessionUtilSpec {
guard let result: UnsafeMutablePointer<config_push_data> = config_push(conf) else { return true } guard let result: UnsafeMutablePointer<config_push_data> = config_push(conf) else { return true }
// We successfully generated the config push and didn't hit the limit // We successfully generated the config push and didn't hit the limit
result.deallocate() free(UnsafeMutableRawPointer(mutating: result))
} }
case 100...200: case 100...200:
@ -2682,7 +2666,7 @@ private extension LibSessionUtilSpec {
guard let result: UnsafeMutablePointer<config_push_data> = config_push(conf) else { return true } guard let result: UnsafeMutablePointer<config_push_data> = config_push(conf) else { return true }
// We successfully generated the config push and didn't hit the limit // We successfully generated the config push and didn't hit the limit
result.deallocate() free(UnsafeMutableRawPointer(mutating: result))
} }
default: default:
@ -2691,7 +2675,7 @@ private extension LibSessionUtilSpec {
guard let result: UnsafeMutablePointer<config_push_data> = config_push(conf) else { return true } guard let result: UnsafeMutablePointer<config_push_data> = config_push(conf) else { return true }
// We successfully generated the config push and didn't hit the limit // We successfully generated the config push and didn't hit the limit
result.deallocate() free(UnsafeMutableRawPointer(mutating: result))
} }
} }
@ -2700,50 +2684,3 @@ private extension LibSessionUtilSpec {
return false return false
} }
} }
private extension Collection where Element == [CChar]? {
/// This creates an array of UnsafePointer types to access data of the C strings in memory. This array provides no automated
/// memory management of it's children so after use you are responsible for handling the life cycle of the child elements and
/// need to call `deallocate()` on each child.
func unsafeCopyCStringArray() throws -> [UnsafePointer<CChar>?] {
return try self.map { value in
guard let value: [CChar] = value else { return nil }
let copy = UnsafeMutableBufferPointer<CChar>.allocate(capacity: value.underestimatedCount)
var remaining: (unwritten: Array<CChar>.Iterator, index: Int) = copy.initialize(from: value)
guard remaining.unwritten.next() == nil else { throw LibSessionError.invalidCConversion }
return UnsafePointer(copy.baseAddress)
}
}
}
private extension Collection where Element == [CChar] {
/// This creates an array of UnsafePointer types to access data of the C strings in memory. This array provides no automated
/// memory management of it's children so after use you are responsible for handling the life cycle of the child elements and
/// need to call `deallocate()` on each child.
func unsafeCopyCStringArray() throws -> [UnsafePointer<CChar>?] {
return try self.map { value in
let copy = UnsafeMutableBufferPointer<CChar>.allocate(capacity: value.underestimatedCount)
var remaining: (unwritten: Array<CChar>.Iterator, index: Int) = copy.initialize(from: value)
guard remaining.unwritten.next() == nil else { throw LibSessionError.invalidCConversion }
return UnsafePointer(copy.baseAddress)
}
}
}
private extension Collection where Element == [UInt8] {
/// This creates an array of UnsafePointer types to access data of the C strings in memory. This array provides no automated
/// memory management of it's children so after use you are responsible for handling the life cycle of the child elements and
/// need to call `deallocate()` on each child.
func unsafeCopyUInt8Array() throws -> [UnsafePointer<UInt8>?] {
return try self.map { value in
let copy = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: value.underestimatedCount)
var remaining: (unwritten: Array<UInt8>.Iterator, index: Int) = copy.initialize(from: value)
guard remaining.unwritten.next() == nil else { throw LibSessionError.invalidCConversion }
return UnsafePointer(copy.baseAddress)
}
}
}

@ -49,7 +49,7 @@ class LibSessionNetwork: NetworkType {
return dependencies return dependencies
.mutate(cache: .libSessionNetwork) { $0.getOrCreateNetwork() } .mutate(cache: .libSessionNetwork) { $0.getOrCreateNetwork() }
.tryMapCallbackWrapper(type: Output.self) { wrapper, network in .tryMapCallbackContext(type: Output.self) { ctx, network in
let sessionId: SessionId = try SessionId(from: swarmPublicKey) let sessionId: SessionId = try SessionId(from: swarmPublicKey)
guard let cSwarmPublicKey: [CChar] = sessionId.publicKeyString.cString(using: .utf8) else { guard let cSwarmPublicKey: [CChar] = sessionId.publicKeyString.cString(using: .utf8) else {
@ -65,7 +65,7 @@ class LibSessionNetwork: NetworkType {
var nodes: Set<LibSession.Snode> = [] var nodes: Set<LibSession.Snode> = []
(0..<swarmSize).forEach { index in nodes.insert(LibSession.Snode(cSwarm[index])) } (0..<swarmSize).forEach { index in nodes.insert(LibSession.Snode(cSwarm[index])) }
CallbackWrapper<Output>.run(ctx, .success(nodes)) CallbackWrapper<Output>.run(ctx, .success(nodes))
}, wrapper.unsafePointer()); }, ctx);
} }
.tryMap { result in try result.successOrThrow() } .tryMap { result in try result.successOrThrow() }
.eraseToAnyPublisher() .eraseToAnyPublisher()
@ -76,7 +76,7 @@ class LibSessionNetwork: NetworkType {
return dependencies return dependencies
.mutate(cache: .libSessionNetwork) { $0.getOrCreateNetwork() } .mutate(cache: .libSessionNetwork) { $0.getOrCreateNetwork() }
.tryMapCallbackWrapper(type: Output.self) { wrapper, network in .tryMapCallbackContext(type: Output.self) { ctx, network in
network_get_random_nodes(network, UInt16(count), { nodesPtr, nodesSize, ctx in network_get_random_nodes(network, UInt16(count), { nodesPtr, nodesSize, ctx in
guard guard
nodesSize > 0, nodesSize > 0,
@ -86,7 +86,7 @@ class LibSessionNetwork: NetworkType {
var nodes: Set<LibSession.Snode> = [] var nodes: Set<LibSession.Snode> = []
(0..<nodesSize).forEach { index in nodes.insert(LibSession.Snode(cSwarm[index])) } (0..<nodesSize).forEach { index in nodes.insert(LibSession.Snode(cSwarm[index])) }
CallbackWrapper<Output>.run(ctx, .success(nodes)) CallbackWrapper<Output>.run(ctx, .success(nodes))
}, wrapper.unsafePointer()); }, ctx);
} }
.tryMap { result in .tryMap { result in
switch result { switch result {
@ -184,7 +184,7 @@ class LibSessionNetwork: NetworkType {
return dependencies return dependencies
.mutate(cache: .libSessionNetwork) { $0.getOrCreateNetwork() } .mutate(cache: .libSessionNetwork) { $0.getOrCreateNetwork() }
.tryMapCallbackWrapper(type: Output.self) { wrapper, network in .tryMapCallbackContext(type: Output.self) { ctx, network in
guard ed25519SecretKey.count == 64 else { throw LibSessionError.invalidCConversion } guard ed25519SecretKey.count == 64 else { throw LibSessionError.invalidCConversion }
var cEd25519SecretKey: [UInt8] = Array(ed25519SecretKey) var cEd25519SecretKey: [UInt8] = Array(ed25519SecretKey)
@ -201,7 +201,7 @@ class LibSessionNetwork: NetworkType {
let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) } let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) }
CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data)) CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data))
}, },
wrapper.unsafePointer() ctx
) )
} }
.tryMap { [dependencies] success, timeout, statusCode, headers, maybeData -> (any ResponseInfoType, AppVersionResponse) in .tryMap { [dependencies] success, timeout, statusCode, headers, maybeData -> (any ResponseInfoType, AppVersionResponse) in
@ -229,7 +229,7 @@ class LibSessionNetwork: NetworkType {
return dependencies return dependencies
.mutate(cache: .libSessionNetwork) { $0.getOrCreateNetwork() } .mutate(cache: .libSessionNetwork) { $0.getOrCreateNetwork() }
.tryMapCallbackWrapper(type: Output.self) { wrapper, network in .tryMapCallbackContext(type: Output.self) { ctx, network in
// Prepare the parameters // Prepare the parameters
let cPayloadBytes: [UInt8] let cPayloadBytes: [UInt8]
@ -274,7 +274,7 @@ class LibSessionNetwork: NetworkType {
let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) } let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) }
CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data)) CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data))
}, },
wrapper.unsafePointer() ctx
) )
case .server: case .server:
@ -292,7 +292,7 @@ class LibSessionNetwork: NetworkType {
let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) } let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) }
CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data)) CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data))
}, },
wrapper.unsafePointer() ctx
) )
} }
@ -314,7 +314,7 @@ class LibSessionNetwork: NetworkType {
let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) } let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) }
CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data)) CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data))
}, },
wrapper.unsafePointer() ctx
) )
} }
@ -331,12 +331,12 @@ class LibSessionNetwork: NetworkType {
let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) } let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) }
CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data)) CallbackWrapper<Output>.run(ctx, (success, timeout, Int(statusCode), headers, data))
}, },
wrapper.unsafePointer() ctx
) )
} }
case .cached(let success, let timeout, let statusCode, let headers, let data): case .cached(let success, let timeout, let statusCode, let headers, let data):
wrapper.run((success, timeout, statusCode, headers, data)) CallbackWrapper<Output>.run(ctx, (success, timeout, statusCode, headers, data))
} }
} }
.tryMap { [dependencies] success, timeout, statusCode, headers, data -> (any ResponseInfoType, Data?) in .tryMap { [dependencies] success, timeout, statusCode, headers, data -> (any ResponseInfoType, Data?) in
@ -410,7 +410,11 @@ class LibSessionNetwork: NetworkType {
private extension LibSessionNetwork { private extension LibSessionNetwork {
class CallbackWrapper<Output> { class CallbackWrapper<Output> {
public let resultPublisher: CurrentValueSubject<Output?, Error> = CurrentValueSubject(nil) public let promise: (Result<Output, Error>) -> Void
init(promise: @escaping (Result<Output, Error>) -> Void) {
self.promise = promise
}
// MARK: - Functions // MARK: - Functions
@ -422,14 +426,14 @@ private extension LibSessionNetwork {
/// Dispatch async so we don't block libSession's internals with Swift logic (which can block other requests) /// Dispatch async so we don't block libSession's internals with Swift logic (which can block other requests)
let wrapper: CallbackWrapper<Output> = Unmanaged<CallbackWrapper<Output>>.fromOpaque(ctx).takeRetainedValue() let wrapper: CallbackWrapper<Output> = Unmanaged<CallbackWrapper<Output>>.fromOpaque(ctx).takeRetainedValue()
DispatchQueue.global(qos: .default).async { [wrapper] in DispatchQueue.global(qos: .default).async { [wrapper] in
wrapper.resultPublisher.send(output) wrapper.promise(.success(output))
} }
} }
public func unsafePointer() -> UnsafeMutableRawPointer { Unmanaged.passRetained(self).toOpaque() } public func unsafePointer() -> UnsafeMutableRawPointer { Unmanaged.passRetained(self).toOpaque() }
public func run(_ output: Output) { public func run(_ output: Output) {
resultPublisher.send(output) promise(.success(output))
} }
} }
} }
@ -437,21 +441,26 @@ private extension LibSessionNetwork {
// MARK: - Publisher Convenience // MARK: - Publisher Convenience
fileprivate extension Publisher { fileprivate extension Publisher {
func tryMapCallbackWrapper<T>( func tryMapCallbackContext<T>(
maxPublishers: Subscribers.Demand = .unlimited, maxPublishers: Subscribers.Demand = .unlimited,
type: T.Type, type: T.Type,
_ transform: @escaping (LibSessionNetwork.CallbackWrapper<T>, Self.Output) throws -> Void _ transform: @escaping (UnsafeMutableRawPointer, Self.Output) throws -> Void
) -> AnyPublisher<T, Error> { ) -> AnyPublisher<T, Error> {
let wrapper: LibSessionNetwork.CallbackWrapper<T> = LibSessionNetwork.CallbackWrapper()
return self return self
.tryMap { value -> Void in try transform(wrapper, value) } .mapError { _ in NetworkError.unknown }
.flatMap { _ in .flatMap { value -> Future<T, Error> in
wrapper Future<T, Error> { promise in
.resultPublisher let wrapper: LibSessionNetwork.CallbackWrapper<T> = LibSessionNetwork.CallbackWrapper(
.compactMap { $0 } promise: promise
.first() )
.eraseToAnyPublisher() let ctx: UnsafeMutableRawPointer = wrapper.unsafePointer()
do { try transform(ctx, value) }
catch {
Unmanaged<LibSessionNetwork.CallbackWrapper<T>>.fromOpaque(ctx).release()
promise(.failure(error))
}
}
} }
.eraseToAnyPublisher() .eraseToAnyPublisher()
} }
@ -788,12 +797,12 @@ public extension LibSession {
// Need to free the nodes within the path as we are the owner // Need to free the nodes within the path as we are the owner
cPaths.forEach { cPath in cPaths.forEach { cPath in
cPath.nodes.deallocate() free(UnsafeMutableRawPointer(mutating: cPath.nodes))
} }
} }
// Need to free the cPathsPtr as we are the owner // Need to free the cPathsPtr as we are the owner
pathsPtr?.deallocate() free(UnsafeMutableRawPointer(mutating: pathsPtr))
// Dispatch async so we don't hold up the libSession thread that triggered the update // Dispatch async so we don't hold up the libSession thread that triggered the update
// or have a reentrancy issue with the mutable cache // or have a reentrancy issue with the mutable cache

@ -14,13 +14,21 @@ public extension Crypto.Generator {
static func randomBytes(_ count: Int) -> Crypto.Generator<Data> { static func randomBytes(_ count: Int) -> Crypto.Generator<Data> {
return Crypto.Generator(id: "randomBytes_Data", args: [count]) { () -> Data in return Crypto.Generator(id: "randomBytes_Data", args: [count]) { () -> Data in
Data(bytes: session_random(count), count: count) let ptr: UnsafeMutablePointer<UInt8> = session_random(count)
let result: Data = Data(bytes: ptr, count: count)
free(ptr)
return result
} }
} }
static func randomBytes(_ count: Int) -> Crypto.Generator<[UInt8]> { static func randomBytes(_ count: Int) -> Crypto.Generator<[UInt8]> {
return Crypto.Generator(id: "randomBytes_[UInt8]", args: [count]) { () -> [UInt8] in return Crypto.Generator(id: "randomBytes_[UInt8]", args: [count]) { () -> [UInt8] in
Array(Data(bytes: session_random(count), count: count)) let ptr: UnsafeMutablePointer<UInt8> = session_random(count)
let result: Data = Data(bytes: ptr, count: count)
free(ptr)
return Array(result)
} }
} }
} }

Loading…
Cancel
Save