From a27eae5fb2dd350271fb92083cf86fe61ef6733d Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 8 Apr 2025 09:56:55 +1000 Subject: [PATCH] Further memory management fixes --- .../Crypto/Crypto+LibSession.swift | 2 +- .../Crypto/Crypto+SessionMessagingKit.swift | 14 +- .../LibSession+GroupKeys.swift | 4 +- .../LibSession/Types/Config.swift | 12 +- .../Crypto/Crypto+OpenGroupAPI.swift | 4 +- .../LibSession/LibSessionUtilSpec.swift | 435 ++++++++---------- .../LibSession/LibSession+Networking.swift | 65 +-- .../Crypto/Crypto+SessionUtilitiesKit.swift | 12 +- 8 files changed, 250 insertions(+), 298 deletions(-) diff --git a/SessionMessagingKit/Crypto/Crypto+LibSession.swift b/SessionMessagingKit/Crypto/Crypto+LibSession.swift index e212a20b9..7ca859eb2 100644 --- a/SessionMessagingKit/Crypto/Crypto+LibSession.swift +++ b/SessionMessagingKit/Crypto/Crypto+LibSession.swift @@ -151,7 +151,7 @@ public extension Crypto.Generator { guard didDecrypt else { throw MessageReceiverError.decryptionFailed } // We need to manually free 'maybePlaintext' upon a successful decryption - defer { maybePlaintext?.deallocate() } + defer { free(UnsafeMutableRawPointer(mutating: maybePlaintext)) } guard plaintextLen > 0, diff --git a/SessionMessagingKit/Crypto/Crypto+SessionMessagingKit.swift b/SessionMessagingKit/Crypto/Crypto+SessionMessagingKit.swift index 902c21ab4..12824c900 100644 --- a/SessionMessagingKit/Crypto/Crypto+SessionMessagingKit.swift +++ b/SessionMessagingKit/Crypto/Crypto+SessionMessagingKit.swift @@ -59,7 +59,7 @@ public extension Crypto.Generator { let ciphertext: Data = maybeCiphertext.map({ Data(bytes: $0, count: ciphertextLen) }) else { throw MessageSenderError.encryptionFailed } - maybeCiphertext?.deallocate() + free(UnsafeMutableRawPointer(mutating: maybeCiphertext)) return ciphertext } @@ -98,9 +98,7 @@ public extension Crypto.Generator { ) let encryptedData: Data? = cEncryptedDataPtr.map { Data(bytes: $0, count: outLen) } - cMessages.forEach { $0?.deallocate() } - cRecipients.forEach { $0?.deallocate() } - cEncryptedDataPtr?.deallocate() + free(UnsafeMutableRawPointer(mutating: cEncryptedDataPtr)) return try encryptedData ?? { throw MessageSenderError.encryptionFailed }() } @@ -145,7 +143,7 @@ public extension Crypto.Generator { let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) }) else { throw MessageReceiverError.decryptionFailed } - maybePlaintext?.deallocate() + free(UnsafeMutableRawPointer(mutating: maybePlaintext)) return (plaintext, String(cString: cSenderSessionId)) } @@ -187,7 +185,7 @@ public extension Crypto.Generator { let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) }) else { throw MessageReceiverError.decryptionFailed } - maybePlaintext?.deallocate() + free(UnsafeMutableRawPointer(mutating: maybePlaintext)) return (plaintext, String(cString: cSenderSessionId)) } @@ -219,7 +217,7 @@ public extension Crypto.Generator { let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) }) else { throw MessageReceiverError.decryptionFailed } - maybePlaintext?.deallocate() + free(UnsafeMutableRawPointer(mutating: maybePlaintext)) return plaintext } @@ -250,7 +248,7 @@ public extension Crypto.Generator { ) let decryptedData: Data? = cDecryptedDataPtr.map { Data(bytes: $0, count: outLen) } - cDecryptedDataPtr?.deallocate() + free(UnsafeMutableRawPointer(mutating: cDecryptedDataPtr)) return try decryptedData ?? { throw MessageReceiverError.decryptionFailed }() } diff --git a/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupKeys.swift b/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupKeys.swift index 5cba9d169..1ceceebd3 100644 --- a/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupKeys.swift +++ b/SessionMessagingKit/LibSession/Config Handling/LibSession+GroupKeys.swift @@ -119,12 +119,12 @@ internal extension LibSession { let cSupplementData: UnsafeMutablePointer = cSupplementData else { throw LibSessionError.failedToKeySupplementGroup } - // Must deallocate on success + // Must free on success let supplementData: Data = Data( bytes: cSupplementData, count: cSupplementDataLen ) - cSupplementData.deallocate() + free(UnsafeMutableRawPointer(mutating: cSupplementData)) return supplementData } diff --git a/SessionMessagingKit/LibSession/Types/Config.swift b/SessionMessagingKit/LibSession/Types/Config.swift index d6eee8374..2ad621683 100644 --- a/SessionMessagingKit/LibSession/Types/Config.swift +++ b/SessionMessagingKit/LibSession/Types/Config.swift @@ -145,7 +145,7 @@ public extension LibSession { count: cPushData.pointee.config_len ) let seqNo: Int64 = cPushData.pointee.seqno - cPushData.deallocate() + free(UnsafeMutableRawPointer(mutating: cPushData)) return PendingChanges.PushData( data: pushData, @@ -201,7 +201,7 @@ public extension LibSession { guard let dumpResult: UnsafeMutablePointer = dumpResult else { return nil } let dumpData: Data = Data(bytes: dumpResult, count: dumpResultLen) - dumpResult.deallocate() + free(UnsafeMutableRawPointer(mutating: dumpResult)) return dumpData } @@ -219,7 +219,7 @@ public extension LibSession { cStringArray: hashList.pointee.value, count: hashList.pointee.len ).defaulting(to: []) - hashList.deallocate() + free(UnsafeMutableRawPointer(mutating: hashList)) return result @@ -232,7 +232,7 @@ public extension LibSession { cStringArray: hashList.pointee.value, count: hashList.pointee.len ).defaulting(to: []) - hashList.deallocate() + free(UnsafeMutableRawPointer(mutating: hashList)) return result } @@ -252,7 +252,7 @@ public extension LibSession { cStringArray: hashList.pointee.value, count: hashList.pointee.len ).defaulting(to: []) - hashList.deallocate() + free(UnsafeMutableRawPointer(mutating: hashList)) return result } @@ -284,7 +284,7 @@ public extension LibSession { .defaulting(to: []) } .defaulting(to: []) - mergedHashesPtr?.deallocate() + free(UnsafeMutableRawPointer(mutating: mergedHashesPtr)) if mergedHashes.count != messages.count { Log.warn(.libSession, "Unable to merge \(messages[0].namespace) messages (\(mergedHashes.count)/\(messages.count))") diff --git a/SessionMessagingKit/Open Groups/Crypto/Crypto+OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/Crypto/Crypto+OpenGroupAPI.swift index b20ef682f..9be17f6bc 100644 --- a/SessionMessagingKit/Open Groups/Crypto/Crypto+OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/Crypto/Crypto+OpenGroupAPI.swift @@ -195,7 +195,7 @@ public extension Crypto.Generator { let ciphertext: Data = maybeCiphertext.map({ Data(bytes: $0, count: ciphertextLen) }) else { throw MessageSenderError.encryptionFailed } - maybeCiphertext?.deallocate() + free(UnsafeMutableRawPointer(mutating: maybeCiphertext)) return ciphertext } @@ -244,7 +244,7 @@ public extension Crypto.Generator { let plaintext: Data = maybePlaintext.map({ Data(bytes: $0, count: plaintextLen) }) else { throw MessageReceiverError.decryptionFailed } - maybePlaintext?.deallocate() + free(UnsafeMutableRawPointer(mutating: maybePlaintext)) return (plaintext, String(cString: cSenderSessionId)) } diff --git a/SessionMessagingKitTests/LibSession/LibSessionUtilSpec.swift b/SessionMessagingKitTests/LibSession/LibSessionUtilSpec.swift index 816888578..fd85781ba 100644 --- a/SessionMessagingKitTests/LibSession/LibSessionUtilSpec.swift +++ b/SessionMessagingKitTests/LibSession/LibSessionUtilSpec.swift @@ -177,7 +177,7 @@ fileprivate extension LibSessionUtilSpec { expect(config_needs_dump(conf)).to(beTrue()) expect { - config_push(conf)?.deallocate() + free(UnsafeMutableRawPointer(mutating: config_push(conf))) try LibSessionError.throwIfNeeded(conf) } .to(throwError(LibSessionError.libSessionError("Config data is too large."))) @@ -292,7 +292,7 @@ fileprivate extension LibSessionUtilSpec { let pushData1: UnsafeMutablePointer = config_push(conf) expect(pushData1.pointee.seqno).to(equal(0)) - pushData1.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData1)) // Update the contact data contact2.set(\.name, to: "Joe") @@ -341,7 +341,7 @@ fileprivate extension LibSessionUtilSpec { config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash1) expect(config_needs_push(conf)).to(beFalse()) 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 // 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 conf2: UnsafeMutablePointer? = nil 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_dump(conf2)).to(beFalse()) let pushData3: UnsafeMutablePointer = config_push(conf2) expect(pushData3.pointee.seqno).to(equal(1)) - pushData3.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData3)) // Because we just called dump() above, to load up contacts2 expect(config_needs_dump(conf)).to(beFalse()) @@ -398,22 +398,21 @@ fileprivate extension LibSessionUtilSpec { // Check the merging let fakeHash2: String = "fakehash2" var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)! - var mergeHashes: [UnsafePointer?] = ((try? [cFakeHash2].unsafeCopyCStringArray()) ?? []) - var mergeData: [UnsafePointer?] = [UnsafePointer(pushData4.pointee.config)] - var mergeSize: [Int] = [pushData4.pointee.config_len] - let mergedHashes: UnsafeMutablePointer? = config_merge(conf, &mergeHashes, &mergeData, &mergeSize, 1) - expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len)) - .to(equal(["fakehash2"])) - config_confirm_pushed(conf2, pushData4.pointee.seqno, &cFakeHash2) - mergeHashes.forEach { $0?.deallocate() } - mergedHashes?.deallocate() - pushData4.deallocate() + try? [fakeHash2].withUnsafeCStrArray { mergeHashes in + var mergeData: [UnsafePointer?] = [UnsafePointer(pushData4.pointee.config)] + var mergeSize: [Int] = [pushData4.pointee.config_len] + let mergedHashes: UnsafeMutablePointer? = config_merge(conf, mergeHashes.baseAddress, &mergeData, &mergeSize, 1) + expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len)) + .to(equal(["fakehash2"])) + config_confirm_pushed(conf2, pushData4.pointee.seqno, &cFakeHash2) + } + free(UnsafeMutableRawPointer(mutating: pushData4)) expect(config_needs_push(conf)).to(beFalse()) let pushData5: UnsafeMutablePointer = config_push(conf) expect(pushData5.pointee.seqno).to(equal(2)) - pushData5.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData5)) // Iterate through and make sure we got everything we expected var sessionIds: [String] = [] @@ -477,27 +476,25 @@ fileprivate extension LibSessionUtilSpec { config_confirm_pushed(conf, pushData6.pointee.seqno, &cFakeHash3a) config_confirm_pushed(conf2, pushData7.pointee.seqno, &cFakeHash3b) - var mergeHashes2: [UnsafePointer?] = ((try? [cFakeHash3b].unsafeCopyCStringArray()) ?? []) - var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData7.pointee.config)] - var mergeSize2: [Int] = [pushData7.pointee.config_len] - let mergedHashes2: UnsafeMutablePointer? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1) - expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) - .to(equal(["fakehash3b"])) + try? [fakeHash3b].withUnsafeCStrArray { mergeHashes2 in + var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData7.pointee.config)] + var mergeSize2: [Int] = [pushData7.pointee.config_len] + let mergedHashes2: UnsafeMutablePointer? = config_merge(conf, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1) + expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) + .to(equal(["fakehash3b"])) + } expect(config_needs_push(conf)).to(beTrue()) - mergeHashes2.forEach { $0?.deallocate() } - mergedHashes2?.deallocate() - pushData7.deallocate() - - var mergeHashes3: [UnsafePointer?] = ((try? [cFakeHash3a].unsafeCopyCStringArray()) ?? []) - var mergeData3: [UnsafePointer?] = [UnsafePointer(pushData6.pointee.config)] - var mergeSize3: [Int] = [pushData6.pointee.config_len] - let mergedHashes3: UnsafeMutablePointer? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1) - expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) - .to(equal(["fakehash3a"])) + free(UnsafeMutableRawPointer(mutating: pushData7)) + + try? [fakeHash3a].withUnsafeCStrArray { mergeHashes3 in + var mergeData3: [UnsafePointer?] = [UnsafePointer(pushData6.pointee.config)] + var mergeSize3: [Int] = [pushData6.pointee.config_len] + let mergedHashes3: UnsafeMutablePointer? = config_merge(conf2, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 1) + expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) + .to(equal(["fakehash3a"])) + } expect(config_needs_push(conf2)).to(beTrue()) - mergeHashes3.forEach { $0?.deallocate() } - mergedHashes3?.deallocate() - pushData6.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData6)) let pushData8: UnsafeMutablePointer = config_push(conf) expect(pushData8.pointee.seqno).to(equal(4)) @@ -517,8 +514,8 @@ fileprivate extension LibSessionUtilSpec { var cFakeHash4: [CChar] = fakeHash4.cString(using: .utf8)! config_confirm_pushed(conf, pushData8.pointee.seqno, &cFakeHash4) config_confirm_pushed(conf2, pushData9.pointee.seqno, &cFakeHash4) - pushData8.deallocate() - pushData9.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData8)) + free(UnsafeMutableRawPointer(mutating: pushData9)) expect(config_needs_push(conf)).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) 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: let fakeHash1: String = "fakehash1" var cFakeHash1: [CChar] = fakeHash1.cString(using: .utf8)! config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash1) - pushData2.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData2)) 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 @@ -694,7 +691,7 @@ fileprivate extension LibSessionUtilSpec { var dump2: UnsafeMutablePointer? = nil var dump2Len: Int = 0 config_dump(conf, &dump2, &dump2Len) - dump2?.deallocate() + free(UnsafeMutableRawPointer(mutating: dump2)) 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 @@ -708,15 +705,14 @@ fileprivate extension LibSessionUtilSpec { // Now imagine we just pulled down the `exp_push1` string from the swarm; we merge it into // conf2: - var mergeHashes: [UnsafePointer?] = ((try? [cFakeHash1].unsafeCopyCStringArray()) ?? []) - var mergeData: [UnsafePointer?] = ((try? [expPush1Encrypted].unsafeCopyUInt8Array()) ?? []) - var mergeSize: [Int] = [expPush1Encrypted.count] - let mergedHashes: UnsafeMutablePointer? = config_merge(conf2, &mergeHashes, &mergeData, &mergeSize, 1) - expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len)) - .to(equal(["fakehash1"])) - mergeHashes.forEach { $0?.deallocate() } - mergeData.forEach { $0?.deallocate() } - mergedHashes?.deallocate() + try? [fakeHash1].withUnsafeCStrArray { mergeHashes in + try? [expPush1Encrypted].withUnsafeUInt8CArray { mergeData in + var mergeSize: [Int] = [expPush1Encrypted.count] + let mergedHashes: UnsafeMutablePointer? = config_merge(conf2, mergeHashes.baseAddress, mergeData.baseAddress, &mergeSize, 1) + expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len)) + .to(equal(["fakehash1"])) + } + } // Our state has changed, so we need to dump: expect(config_needs_dump(conf2)).to(beTrue()) @@ -724,7 +720,7 @@ fileprivate extension LibSessionUtilSpec { var dump3Len: Int = 0 config_dump(conf2, &dump3, &dump3Len) // (store in db) - dump3?.deallocate() + free(UnsafeMutableRawPointer(mutating: dump3)) 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 @@ -777,8 +773,8 @@ fileprivate extension LibSessionUtilSpec { var dump5Len: Int = 0 config_dump(conf2, &dump5, &dump5Len); // (store in db) - dump4?.deallocate() - dump5?.deallocate() + free(UnsafeMutableRawPointer(mutating: dump4)) + free(UnsafeMutableRawPointer(mutating: dump5)) // Since we set different things, we're going to get back different serialized data to be // pushed: @@ -791,25 +787,23 @@ fileprivate extension LibSessionUtilSpec { // Feed the new config into each other. (This array could hold multiple configs if we pulled // down more than one). - var mergeHashes2: [UnsafePointer?] = ((try? [cFakeHash2].unsafeCopyCStringArray()) ?? []) - var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData3.pointee.config)] - var mergeSize2: [Int] = [pushData3.pointee.config_len] - let mergedHashes2: UnsafeMutablePointer? = config_merge(conf2, &mergeHashes2, &mergeData2, &mergeSize2, 1) - expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) - .to(equal(["fakehash2"])) - mergeHashes2.forEach { $0?.deallocate() } - mergedHashes2?.deallocate() - pushData3.deallocate() - - var mergeHashes3: [UnsafePointer?] = ((try? [cFakeHash3].unsafeCopyCStringArray()) ?? []) - var mergeData3: [UnsafePointer?] = [UnsafePointer(pushData4.pointee.config)] - var mergeSize3: [Int] = [pushData4.pointee.config_len] - let mergedHashes3: UnsafeMutablePointer? = config_merge(conf, &mergeHashes3, &mergeData3, &mergeSize3, 1) - expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) - .to(equal(["fakehash3"])) - mergeHashes3.forEach { $0?.deallocate() } - mergedHashes3?.deallocate() - pushData4.deallocate() + try? [fakeHash2].withUnsafeCStrArray { mergeHashes2 in + var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData3.pointee.config)] + var mergeSize2: [Int] = [pushData3.pointee.config_len] + let mergedHashes2: UnsafeMutablePointer? = config_merge(conf2, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1) + expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) + .to(equal(["fakehash2"])) + } + free(UnsafeMutableRawPointer(mutating: pushData3)) + + try? [fakeHash3].withUnsafeCStrArray { mergeHashes3 in + var mergeData3: [UnsafePointer?] = [UnsafePointer(pushData4.pointee.config)] + var mergeSize3: [Int] = [pushData4.pointee.config_len] + let mergedHashes3: UnsafeMutablePointer? = config_merge(conf, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 1) + expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) + .to(equal(["fakehash3"])) + } + free(UnsafeMutableRawPointer(mutating: pushData4)) // Now after the merge we *will* want to push from both client, since both will have generated a // merge conflict update (with seqno = 3). @@ -849,8 +843,8 @@ fileprivate extension LibSessionUtilSpec { var cFakeHash5: [CChar] = fakeHash5.cString(using: .utf8)! config_confirm_pushed(conf, pushData5.pointee.seqno, &cFakeHash4) config_confirm_pushed(conf2, pushData6.pointee.seqno, &cFakeHash5) - pushData5.deallocate() - pushData6.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData5)) + free(UnsafeMutableRawPointer(mutating: pushData6)) var dump6: UnsafeMutablePointer? = nil var dump6Len: Int = 0 @@ -859,8 +853,8 @@ fileprivate extension LibSessionUtilSpec { var dump7Len: Int = 0 config_dump(conf2, &dump7, &dump7Len); // (store in db) - dump6?.deallocate() - dump7?.deallocate() + free(UnsafeMutableRawPointer(mutating: dump6)) + free(UnsafeMutableRawPointer(mutating: dump7)) expect(config_needs_dump(conf)).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 // after the test - conf?.deallocate() - conf2?.deallocate() + free(UnsafeMutableRawPointer(mutating: conf)) + free(UnsafeMutableRawPointer(mutating: conf2)) } } } @@ -968,7 +962,7 @@ fileprivate extension LibSessionUtilSpec { config_confirm_pushed(conf, pushData1.pointee.seqno, &cFakeHash1) expect(config_needs_dump(conf)).to(beTrue()) expect(config_needs_push(conf)).to(beFalse()) - pushData1.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData1)) var dump1: UnsafeMutablePointer? = nil var dump1Len: Int = 0 @@ -977,7 +971,7 @@ fileprivate extension LibSessionUtilSpec { var error2: [CChar] = [CChar](repeating: 0, count: 256) var conf2: UnsafeMutablePointer? = nil 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_push(conf2)).to(beFalse()) @@ -1017,16 +1011,15 @@ fileprivate extension LibSessionUtilSpec { // Check the merging let fakeHash2: String = "fakehash2" var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)! - var mergeHashes: [UnsafePointer?] = ((try? [cFakeHash2].unsafeCopyCStringArray()) ?? []) - var mergeData: [UnsafePointer?] = [UnsafePointer(pushData2.pointee.config)] - var mergeSize: [Int] = [pushData2.pointee.config_len] - let mergedHashes: UnsafeMutablePointer? = config_merge(conf, &mergeHashes, &mergeData, &mergeSize, 1) - expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len)) - .to(equal(["fakehash2"])) - config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash2) - mergeHashes.forEach { $0?.deallocate() } - mergedHashes?.deallocate() - pushData2.deallocate() + try? [fakeHash2].withUnsafeCStrArray { mergeHashes in + var mergeData: [UnsafePointer?] = [UnsafePointer(pushData2.pointee.config)] + var mergeSize: [Int] = [pushData2.pointee.config_len] + let mergedHashes: UnsafeMutablePointer? = config_merge(conf, mergeHashes.baseAddress, &mergeData, &mergeSize, 1) + expect([String](cStringArray: mergedHashes?.pointee.value, count: mergedHashes?.pointee.len)) + .to(equal(["fakehash2"])) + config_confirm_pushed(conf, pushData2.pointee.seqno, &cFakeHash2) + } + free(UnsafeMutableRawPointer(mutating: pushData2)) 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)) .to(beEmpty()) expect(pushData1.pointee.config_len).to(equal(432)) - pushData1.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData1)) let users: [String] = [ "050000000000000000000000000000000000000000000000000000000000000000", @@ -1303,7 +1296,7 @@ fileprivate extension LibSessionUtilSpec { var error2: [CChar] = [CChar](repeating: 0, count: 256) var conf2: UnsafeMutablePointer? = nil 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_push(conf)).to(beFalse()) @@ -1312,12 +1305,12 @@ fileprivate extension LibSessionUtilSpec { expect(pushData3.pointee.seqno).to(equal(1)) expect([String](cStringArray: pushData3.pointee.obsolete, count: pushData3.pointee.obsolete_len)) .to(beEmpty()) - pushData3.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData3)) let currentHashes1: UnsafeMutablePointer? = config_current_hashes(conf) expect([String](cStringArray: currentHashes1?.pointee.value, count: currentHashes1?.pointee.len)) .to(equal(["fakehash1"])) - currentHashes1?.deallocate() + free(UnsafeMutableRawPointer(mutating: currentHashes1)) expect(config_needs_push(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([String](cStringArray: pushData4.pointee.obsolete, count: pushData4.pointee.obsolete_len)) .to(beEmpty()) - pushData4.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData4)) let currentHashes2: UnsafeMutablePointer? = config_current_hashes(conf2) expect([String](cStringArray: currentHashes2?.pointee.value, count: currentHashes2?.pointee.len)) .to(equal(["fakehash1"])) - currentHashes2?.deallocate() + free(UnsafeMutableRawPointer(mutating: currentHashes2)) expect(user_groups_size(conf2)).to(equal(2)) expect(user_groups_size_communities(conf2)).to(equal(1)) @@ -1375,7 +1368,7 @@ fileprivate extension LibSessionUtilSpec { let pushData5: UnsafeMutablePointer = config_push(conf2) expect(pushData5.pointee.seqno).to(equal(1)) expect(config_needs_dump(conf2)).to(beFalse()) - pushData5.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData5)) for targetConf in [conf, conf2] { // Iterate through and make sure we got everything we expected @@ -1427,7 +1420,7 @@ fileprivate extension LibSessionUtilSpec { let pushData6: UnsafeMutablePointer = config_push(conf2) expect(pushData6.pointee.seqno).to(equal(1)) expect(config_needs_dump(conf2)).to(beFalse()) - pushData6.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData6)) community2.set(\.room, to: "sudokuRoom") // Change capitalization user_groups_set_community(conf2, &community2) @@ -1446,7 +1439,7 @@ fileprivate extension LibSessionUtilSpec { let currentHashes3: UnsafeMutablePointer? = config_current_hashes(conf2) expect([String](cStringArray: currentHashes3?.pointee.value, count: currentHashes3?.pointee.len)) .to(equal([fakeHash2])) - currentHashes3?.deallocate() + free(UnsafeMutableRawPointer(mutating: currentHashes3)) var dump2: UnsafeMutablePointer? = nil var dump2Len: Int = 0 @@ -1460,15 +1453,14 @@ fileprivate extension LibSessionUtilSpec { config_confirm_pushed(conf2, pushData8.pointee.seqno, &cFakeHash2) expect(config_needs_dump(conf2)).to(beFalse()) - var mergeHashes1: [UnsafePointer?] = ((try? [cFakeHash2].unsafeCopyCStringArray()) ?? []) - var mergeData1: [UnsafePointer?] = [UnsafePointer(pushData8.pointee.config)] - var mergeSize1: [Int] = [pushData8.pointee.config_len] - let mergedHashes1: UnsafeMutablePointer? = config_merge(conf, &mergeHashes1, &mergeData1, &mergeSize1, 1) - expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len)) - .to(equal(["fakehash2"])) - mergeHashes1.forEach { $0?.deallocate() } - mergedHashes1?.deallocate() - pushData8.deallocate() + try? [fakeHash2].withUnsafeCStrArray { mergeHashes1 in + var mergeData1: [UnsafePointer?] = [UnsafePointer(pushData8.pointee.config)] + var mergeSize1: [Int] = [pushData8.pointee.config_len] + let mergedHashes1: UnsafeMutablePointer? = config_merge(conf, mergeHashes1.baseAddress, &mergeData1, &mergeSize1, 1) + expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len)) + .to(equal(["fakehash2"])) + } + free(UnsafeMutableRawPointer(mutating: pushData8)) var cCommunity3BaseUrl: [CChar] = "http://example.org:5678".cString(using: .utf8)! var cCommunity3Room: [CChar] = "SudokuRoom".cString(using: .utf8)! @@ -1493,7 +1485,7 @@ fileprivate extension LibSessionUtilSpec { let pushData9: UnsafeMutablePointer = config_push(conf2) expect(pushData9.pointee.seqno).to(equal(2)) expect(config_needs_dump(conf2)).to(beFalse()) - pushData9.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData9)) user_groups_set_free_legacy_group(conf2, legacyGroup5) expect(config_needs_push(conf2)).to(beTrue()) @@ -1515,16 +1507,15 @@ fileprivate extension LibSessionUtilSpec { let currentHashes4: UnsafeMutablePointer? = config_current_hashes(conf2) expect([String](cStringArray: currentHashes4?.pointee.value, count: currentHashes4?.pointee.len)) .to(equal([fakeHash3])) - currentHashes4?.deallocate() - - var mergeHashes2: [UnsafePointer?] = ((try? [cFakeHash3].unsafeCopyCStringArray()) ?? []) - var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData10.pointee.config)] - var mergeSize2: [Int] = [pushData10.pointee.config_len] - let mergedHashes2: UnsafeMutablePointer? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1) - expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) - .to(equal(["fakehash3"])) - mergeHashes2.forEach { $0?.deallocate() } - mergedHashes2?.deallocate() + free(UnsafeMutableRawPointer(mutating: currentHashes4)) + + try? [fakeHash3].withUnsafeCStrArray { mergeHashes2 in + var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData10.pointee.config)] + var mergeSize2: [Int] = [pushData10.pointee.config_len] + let mergedHashes2: UnsafeMutablePointer? = config_merge(conf, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1) + expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) + .to(equal(["fakehash3"])) + } expect(user_groups_size(conf)).to(equal(1)) expect(user_groups_size_communities(conf)).to(equal(0)) @@ -1566,41 +1557,40 @@ fileprivate extension LibSessionUtilSpec { let cFakeHash11: [CChar] = fakeHash11.cString(using: .utf8)! let fakeHash12: String = "fakehash12" let cFakeHash12: [CChar] = fakeHash12.cString(using: .utf8)! - var mergeHashes3: [UnsafePointer?] = ((try? [cFakeHash10, cFakeHash11, cFakeHash12, cFakeHash4].unsafeCopyCStringArray()) ?? []) - var mergeData3: [UnsafePointer?] = [ - UnsafePointer(pushData10.pointee.config), - UnsafePointer(pushData2.pointee.config), - UnsafePointer(pushData7.pointee.config), - UnsafePointer(pushData11.pointee.config) - ] - var mergeSize3: [Int] = [ - pushData10.pointee.config_len, - pushData2.pointee.config_len, - pushData7.pointee.config_len, - pushData11.pointee.config_len - ] - let mergedHashes3: UnsafeMutablePointer? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 4) - expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) - .to(equal(["fakehash10", "fakehash11", "fakehash12", "fakehash4"])) - expect(config_needs_dump(conf2)).to(beTrue()) - expect(config_needs_push(conf2)).to(beFalse()) - mergeHashes3.forEach { $0?.deallocate() } - mergedHashes3?.deallocate() - pushData2.deallocate() - pushData7.deallocate() - pushData10.deallocate() - pushData11.deallocate() + try? [fakeHash10, fakeHash11, fakeHash12, fakeHash4].withUnsafeCStrArray { mergeHashes3 in + var mergeData3: [UnsafePointer?] = [ + UnsafePointer(pushData10.pointee.config), + UnsafePointer(pushData2.pointee.config), + UnsafePointer(pushData7.pointee.config), + UnsafePointer(pushData11.pointee.config) + ] + var mergeSize3: [Int] = [ + pushData10.pointee.config_len, + pushData2.pointee.config_len, + pushData7.pointee.config_len, + pushData11.pointee.config_len + ] + let mergedHashes3: UnsafeMutablePointer? = config_merge(conf2, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 4) + expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) + .to(equal(["fakehash10", "fakehash11", "fakehash12", "fakehash4"])) + expect(config_needs_dump(conf2)).to(beTrue()) + expect(config_needs_push(conf2)).to(beFalse()) + } + free(UnsafeMutableRawPointer(mutating: pushData2)) + free(UnsafeMutableRawPointer(mutating: pushData7)) + free(UnsafeMutableRawPointer(mutating: pushData10)) + free(UnsafeMutableRawPointer(mutating: pushData11)) let currentHashes5: UnsafeMutablePointer? = config_current_hashes(conf2) expect([String](cStringArray: currentHashes5?.pointee.value, count: currentHashes5?.pointee.len)) .to(equal([fakeHash4])) - currentHashes5?.deallocate() + free(UnsafeMutableRawPointer(mutating: currentHashes5)) let pushData12: UnsafeMutablePointer = config_push(conf2) expect(pushData12.pointee.seqno).to(equal(4)) expect([String](cStringArray: pushData12.pointee.obsolete, count: pushData12.pointee.obsolete_len)) .to(equal([fakeHash11, fakeHash12, fakeHash10, fakeHash3])) - pushData12.deallocate() + free(UnsafeMutableRawPointer(mutating: pushData12)) for targetConf in [conf, conf2] { // 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_dump(conf)).to(beTrue()) - var mergeHashes1: [UnsafePointer?] = try! [cFakeHash1].unsafeCopyCStringArray() - var mergeData1: [UnsafePointer?] = [UnsafePointer(pushData1.pointee.config)] - var mergeSize1: [Int] = [pushData1.pointee.config_len] - let mergedHashes1: UnsafeMutablePointer? = config_merge(conf2, &mergeHashes1, &mergeData1, &mergeSize1, 1) - expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len)) - .to(equal(["fakehash1"])) - expect(config_needs_push(conf2)).to(beFalse()) - mergeHashes1.forEach { $0?.deallocate() } - mergedHashes1?.deallocate() - pushData1.deallocate() + try? [fakeHash1].withUnsafeCStrArray { mergeHashes1 in + var mergeData1: [UnsafePointer?] = [UnsafePointer(pushData1.pointee.config)] + var mergeSize1: [Int] = [pushData1.pointee.config_len] + let mergedHashes1: UnsafeMutablePointer? = config_merge(conf2, mergeHashes1.baseAddress, &mergeData1, &mergeSize1, 1) + expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len)) + .to(equal(["fakehash1"])) + expect(config_needs_push(conf2)).to(beFalse()) + } + free(UnsafeMutableRawPointer(mutating: pushData1)) let namePtr: UnsafePointer? = groups_info_get_name(conf2) let descPtr: UnsafePointer? = groups_info_get_description(conf2) @@ -1757,14 +1746,13 @@ fileprivate extension LibSessionUtilSpec { var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)! config_confirm_pushed(conf2, pushData2.pointee.seqno, &cFakeHash2) - var mergeHashes2: [UnsafePointer?] = try! [cFakeHash2].unsafeCopyCStringArray() - var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData2.pointee.config)] - var mergeSize2: [Int] = [pushData2.pointee.config_len] - let mergedHashes2: UnsafeMutablePointer? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1) - expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) - .to(equal(["fakehash2"])) - mergeHashes2.forEach { $0?.deallocate() } - mergedHashes2?.deallocate() + try? [fakeHash2].withUnsafeCStrArray { mergeHashes2 in + var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData2.pointee.config)] + var mergeSize2: [Int] = [pushData2.pointee.config_len] + let mergedHashes2: UnsafeMutablePointer? = config_merge(conf, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1) + expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) + .to(equal(["fakehash2"])) + } 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)) @@ -1795,15 +1783,14 @@ fileprivate extension LibSessionUtilSpec { var cFakeHash3: [CChar] = fakeHash3.cString(using: .utf8)! config_confirm_pushed(conf, pushData3.pointee.seqno, &cFakeHash3) - var mergeHashes3: [UnsafePointer?] = try! [cFakeHash3].unsafeCopyCStringArray() - var mergeData3: [UnsafePointer?] = [UnsafePointer(pushData3.pointee.config)] - var mergeSize3: [Int] = [pushData3.pointee.config_len] - let mergedHashes3: UnsafeMutablePointer? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1) - expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) - .to(equal(["fakehash3"])) - mergeHashes3.forEach { $0?.deallocate() } - mergedHashes3?.deallocate() - pushData3.deallocate() + try? [fakeHash3].withUnsafeCStrArray { mergeHashes3 in + var mergeData3: [UnsafePointer?] = [UnsafePointer(pushData3.pointee.config)] + var mergeSize3: [Int] = [pushData3.pointee.config_len] + let mergedHashes3: UnsafeMutablePointer? = config_merge(conf2, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 1) + expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) + .to(equal(["fakehash3"])) + } + free(UnsafeMutableRawPointer(mutating: pushData3)) let namePtr3: UnsafePointer? = groups_info_get_name(conf2) let descPtr3: UnsafePointer? = groups_info_get_description(conf2) @@ -2064,16 +2051,15 @@ fileprivate extension LibSessionUtilSpec { expect(config_needs_push(conf)).to(beFalse()) expect(config_needs_dump(conf)).to(beTrue()) - var mergeHashes1: [UnsafePointer?] = try! [cFakeHash1].unsafeCopyCStringArray() - var mergeData1: [UnsafePointer?] = [UnsafePointer(pushData1.pointee.config)] - var mergeSize1: [Int] = [pushData1.pointee.config_len] - let mergedHashes1: UnsafeMutablePointer? = config_merge(conf2, &mergeHashes1, &mergeData1, &mergeSize1, 1) - expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len)) - .to(equal(["fakehash1"])) - expect(config_needs_push(conf2)).to(beFalse()) - mergeHashes1.forEach { $0?.deallocate() } - mergedHashes1?.deallocate() - pushData1.deallocate() + try? [fakeHash1].withUnsafeCStrArray { mergeHashes1 in + var mergeData1: [UnsafePointer?] = [UnsafePointer(pushData1.pointee.config)] + var mergeSize1: [Int] = [pushData1.pointee.config_len] + let mergedHashes1: UnsafeMutablePointer? = config_merge(conf2, mergeHashes1.baseAddress, &mergeData1, &mergeSize1, 1) + expect([String](cStringArray: mergedHashes1?.pointee.value, count: mergedHashes1?.pointee.len)) + .to(equal(["fakehash1"])) + expect(config_needs_push(conf2)).to(beFalse()) + } + free(UnsafeMutableRawPointer(mutating: pushData1)) expect(groups_members_size(conf2)).to(equal(25)) @@ -2171,14 +2157,13 @@ fileprivate extension LibSessionUtilSpec { var cFakeHash2: [CChar] = fakeHash2.cString(using: .utf8)! config_confirm_pushed(conf2, pushData2.pointee.seqno, &cFakeHash2) - var mergeHashes2: [UnsafePointer?] = try! [cFakeHash2].unsafeCopyCStringArray() - var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData2.pointee.config)] - var mergeSize2: [Int] = [pushData2.pointee.config_len] - let mergedHashes2: UnsafeMutablePointer? = config_merge(conf, &mergeHashes2, &mergeData2, &mergeSize2, 1) - expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) - .to(equal(["fakehash2"])) - mergeHashes2.forEach { $0?.deallocate() } - mergedHashes2?.deallocate() + try? [fakeHash2].withUnsafeCStrArray { mergeHashes2 in + var mergeData2: [UnsafePointer?] = [UnsafePointer(pushData2.pointee.config)] + var mergeSize2: [Int] = [pushData2.pointee.config_len] + let mergedHashes2: UnsafeMutablePointer? = config_merge(conf, mergeHashes2.baseAddress, &mergeData2, &mergeSize2, 1) + expect([String](cStringArray: mergedHashes2?.pointee.value, count: mergedHashes2?.pointee.len)) + .to(equal(["fakehash2"])) + } var cSessionId2: [CChar] = sids[23].cString(using: .utf8)! var member2: config_group_member = config_group_member() @@ -2344,14 +2329,13 @@ fileprivate extension LibSessionUtilSpec { var cFakeHash3: [CChar] = fakeHash3.cString(using: .utf8)! config_confirm_pushed(conf, pushData3.pointee.seqno, &cFakeHash3) - var mergeHashes3: [UnsafePointer?] = try! [cFakeHash3].unsafeCopyCStringArray() - var mergeData3: [UnsafePointer?] = [UnsafePointer(pushData3.pointee.config)] - var mergeSize3: [Int] = [pushData3.pointee.config_len] - let mergedHashes3: UnsafeMutablePointer? = config_merge(conf2, &mergeHashes3, &mergeData3, &mergeSize3, 1) - expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) - .to(equal(["fakehash3"])) - mergeHashes3.forEach { $0?.deallocate() } - mergedHashes3?.deallocate() + try? [fakeHash3].withUnsafeCStrArray { mergeHashes3 in + var mergeData3: [UnsafePointer?] = [UnsafePointer(pushData3.pointee.config)] + var mergeSize3: [Int] = [pushData3.pointee.config_len] + let mergedHashes3: UnsafeMutablePointer? = config_merge(conf2, mergeHashes3.baseAddress, &mergeData3, &mergeSize3, 1) + expect([String](cStringArray: mergedHashes3?.pointee.value, count: mergedHashes3?.pointee.len)) + .to(equal(["fakehash3"])) + } expect(groups_members_size(conf2)).to(equal(48)) // 18 deleted earlier @@ -2539,7 +2523,7 @@ fileprivate extension LibSessionUtilSpec { groups_keys_dump(keysConf, &dumpResult, &dumpResultLen) let dumpData: Data = Data(bytes: dumpResult!, count: dumpResultLen) - dumpResult?.deallocate() + free(UnsafeMutableRawPointer(mutating: dumpResult)) return dumpData.toHexString() } @@ -2665,7 +2649,7 @@ private extension LibSessionUtilSpec { guard let result: UnsafeMutablePointer = config_push(conf) else { return true } // We successfully generated the config push and didn't hit the limit - result.deallocate() + free(UnsafeMutableRawPointer(mutating: result)) case 50...100: // 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(conf) else { return true } // We successfully generated the config push and didn't hit the limit - result.deallocate() + free(UnsafeMutableRawPointer(mutating: result)) } case 100...200: @@ -2682,7 +2666,7 @@ private extension LibSessionUtilSpec { guard let result: UnsafeMutablePointer = config_push(conf) else { return true } // We successfully generated the config push and didn't hit the limit - result.deallocate() + free(UnsafeMutableRawPointer(mutating: result)) } default: @@ -2691,7 +2675,7 @@ private extension LibSessionUtilSpec { guard let result: UnsafeMutablePointer = config_push(conf) else { return true } // 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 } } - -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?] { - return try self.map { value in - guard let value: [CChar] = value else { return nil } - - let copy = UnsafeMutableBufferPointer.allocate(capacity: value.underestimatedCount) - var remaining: (unwritten: Array.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?] { - return try self.map { value in - let copy = UnsafeMutableBufferPointer.allocate(capacity: value.underestimatedCount) - var remaining: (unwritten: Array.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?] { - return try self.map { value in - let copy = UnsafeMutableBufferPointer.allocate(capacity: value.underestimatedCount) - var remaining: (unwritten: Array.Iterator, index: Int) = copy.initialize(from: value) - guard remaining.unwritten.next() == nil else { throw LibSessionError.invalidCConversion } - - return UnsafePointer(copy.baseAddress) - } - } -} diff --git a/SessionSnodeKit/LibSession/LibSession+Networking.swift b/SessionSnodeKit/LibSession/LibSession+Networking.swift index 3d314fc36..d2f83bbc6 100644 --- a/SessionSnodeKit/LibSession/LibSession+Networking.swift +++ b/SessionSnodeKit/LibSession/LibSession+Networking.swift @@ -49,7 +49,7 @@ class LibSessionNetwork: NetworkType { return dependencies .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) guard let cSwarmPublicKey: [CChar] = sessionId.publicKeyString.cString(using: .utf8) else { @@ -65,7 +65,7 @@ class LibSessionNetwork: NetworkType { var nodes: Set = [] (0...run(ctx, .success(nodes)) - }, wrapper.unsafePointer()); + }, ctx); } .tryMap { result in try result.successOrThrow() } .eraseToAnyPublisher() @@ -76,7 +76,7 @@ class LibSessionNetwork: NetworkType { return dependencies .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 guard nodesSize > 0, @@ -86,7 +86,7 @@ class LibSessionNetwork: NetworkType { var nodes: Set = [] (0...run(ctx, .success(nodes)) - }, wrapper.unsafePointer()); + }, ctx); } .tryMap { result in switch result { @@ -184,7 +184,7 @@ class LibSessionNetwork: NetworkType { return dependencies .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 } var cEd25519SecretKey: [UInt8] = Array(ed25519SecretKey) @@ -201,7 +201,7 @@ class LibSessionNetwork: NetworkType { let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) } CallbackWrapper.run(ctx, (success, timeout, Int(statusCode), headers, data)) }, - wrapper.unsafePointer() + ctx ) } .tryMap { [dependencies] success, timeout, statusCode, headers, maybeData -> (any ResponseInfoType, AppVersionResponse) in @@ -229,7 +229,7 @@ class LibSessionNetwork: NetworkType { return dependencies .mutate(cache: .libSessionNetwork) { $0.getOrCreateNetwork() } - .tryMapCallbackWrapper(type: Output.self) { wrapper, network in + .tryMapCallbackContext(type: Output.self) { ctx, network in // Prepare the parameters let cPayloadBytes: [UInt8] @@ -274,7 +274,7 @@ class LibSessionNetwork: NetworkType { let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) } CallbackWrapper.run(ctx, (success, timeout, Int(statusCode), headers, data)) }, - wrapper.unsafePointer() + ctx ) case .server: @@ -292,7 +292,7 @@ class LibSessionNetwork: NetworkType { let data: Data? = dataPtr.map { Data(bytes: $0, count: dataLen) } CallbackWrapper.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) } CallbackWrapper.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) } CallbackWrapper.run(ctx, (success, timeout, Int(statusCode), headers, data)) }, - wrapper.unsafePointer() + ctx ) } case .cached(let success, let timeout, let statusCode, let headers, let data): - wrapper.run((success, timeout, statusCode, headers, data)) + CallbackWrapper.run(ctx, (success, timeout, statusCode, headers, data)) } } .tryMap { [dependencies] success, timeout, statusCode, headers, data -> (any ResponseInfoType, Data?) in @@ -410,7 +410,11 @@ class LibSessionNetwork: NetworkType { private extension LibSessionNetwork { class CallbackWrapper { - public let resultPublisher: CurrentValueSubject = CurrentValueSubject(nil) + public let promise: (Result) -> Void + + init(promise: @escaping (Result) -> Void) { + self.promise = promise + } // 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) let wrapper: CallbackWrapper = Unmanaged>.fromOpaque(ctx).takeRetainedValue() 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 run(_ output: Output) { - resultPublisher.send(output) + promise(.success(output)) } } } @@ -437,21 +441,26 @@ private extension LibSessionNetwork { // MARK: - Publisher Convenience fileprivate extension Publisher { - func tryMapCallbackWrapper( + func tryMapCallbackContext( maxPublishers: Subscribers.Demand = .unlimited, type: T.Type, - _ transform: @escaping (LibSessionNetwork.CallbackWrapper, Self.Output) throws -> Void + _ transform: @escaping (UnsafeMutableRawPointer, Self.Output) throws -> Void ) -> AnyPublisher { - let wrapper: LibSessionNetwork.CallbackWrapper = LibSessionNetwork.CallbackWrapper() - return self - .tryMap { value -> Void in try transform(wrapper, value) } - .flatMap { _ in - wrapper - .resultPublisher - .compactMap { $0 } - .first() - .eraseToAnyPublisher() + .mapError { _ in NetworkError.unknown } + .flatMap { value -> Future in + Future { promise in + let wrapper: LibSessionNetwork.CallbackWrapper = LibSessionNetwork.CallbackWrapper( + promise: promise + ) + let ctx: UnsafeMutableRawPointer = wrapper.unsafePointer() + + do { try transform(ctx, value) } + catch { + Unmanaged>.fromOpaque(ctx).release() + promise(.failure(error)) + } + } } .eraseToAnyPublisher() } @@ -788,12 +797,12 @@ public extension LibSession { // Need to free the nodes within the path as we are the owner cPaths.forEach { cPath in - cPath.nodes.deallocate() + free(UnsafeMutableRawPointer(mutating: cPath.nodes)) } } // 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 // or have a reentrancy issue with the mutable cache diff --git a/SessionUtilitiesKit/Crypto/Crypto+SessionUtilitiesKit.swift b/SessionUtilitiesKit/Crypto/Crypto+SessionUtilitiesKit.swift index 2fc5189fb..a6df9b00f 100644 --- a/SessionUtilitiesKit/Crypto/Crypto+SessionUtilitiesKit.swift +++ b/SessionUtilitiesKit/Crypto/Crypto+SessionUtilitiesKit.swift @@ -14,13 +14,21 @@ public extension Crypto.Generator { static func randomBytes(_ count: Int) -> Crypto.Generator { return Crypto.Generator(id: "randomBytes_Data", args: [count]) { () -> Data in - Data(bytes: session_random(count), count: count) + let ptr: UnsafeMutablePointer = session_random(count) + let result: Data = Data(bytes: ptr, count: count) + free(ptr) + + return result } } static func randomBytes(_ count: Int) -> Crypto.Generator<[UInt8]> { return Crypto.Generator(id: "randomBytes_[UInt8]", args: [count]) { () -> [UInt8] in - Array(Data(bytes: session_random(count), count: count)) + let ptr: UnsafeMutablePointer = session_random(count) + let result: Data = Data(bytes: ptr, count: count) + free(ptr) + + return Array(result) } } }