From 33e25d757d9980278c62f3761b816a55561030ab Mon Sep 17 00:00:00 2001 From: ankuper Date: Fri, 3 Jul 2026 03:25:17 -0400 Subject: [PATCH] fix(animation-cache): stop double-freeing DecompressedData.stream on failed init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit compression_stream_init() failure was manually deallocating self.stream before returning nil. Since all stored properties are already assigned by that point, Swift still calls deinit on the failed-init instance, which unconditionally destroys+deallocates self.stream again — a double free that libsystem_malloc catches as "pointer being freed was not allocated" (SIGABRT, DCTMultiAnimationRenderer-FirstFrame queue, build 33197). Let deinit be the sole owner of that cleanup. --- .../Sources/DCTAnimationCacheImpl.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/submodules/TelegramUI/Components/DCTAnimationCacheImpl/Sources/DCTAnimationCacheImpl.swift b/submodules/TelegramUI/Components/DCTAnimationCacheImpl/Sources/DCTAnimationCacheImpl.swift index cd2c8f6e37e..6c23275110e 100644 --- a/submodules/TelegramUI/Components/DCTAnimationCacheImpl/Sources/DCTAnimationCacheImpl.swift +++ b/submodules/TelegramUI/Components/DCTAnimationCacheImpl/Sources/DCTAnimationCacheImpl.swift @@ -971,8 +971,16 @@ private final class DecompressedData { self.dataRange = dataRange self.stream = UnsafeMutablePointer.allocate(capacity: 1) + // Do NOT deallocate self.stream here on failure: since all stored + // properties (incl. self.stream) are already assigned at this point, + // Swift's ARC still calls deinit on this failed-init instance once + // `return nil` executes below — and deinit unconditionally destroys + // and deallocates self.stream too. Deallocating it here as well was a + // double free (libsystem_malloc "pointer being freed was not + // allocated" -> SIGABRT, seen in the field on rare + // compression_stream_init failures). Let deinit be the single owner + // of that cleanup. guard compression_stream_init(self.stream, COMPRESSION_STREAM_DECODE, algorithm) != COMPRESSION_STATUS_ERROR else { - self.stream.deallocate() return nil }