From 368b585124af07c76227a87d159a44a925ef75f4 Mon Sep 17 00:00:00 2001 From: Val Lorentz Date: Sat, 10 Feb 2024 09:53:13 +0100 Subject: [PATCH] Preallocate vector storing decrypted files Vectors grow in powers of two while reading, which is doubly wasteful: * causes every byte to be copied in average once * leaves the vector in average 25% larger than it needs to be, wasting memory. For example, adding this test to `crates/matrix-sdk-crypto/src/file_encryption/attachments.rs`: ``` fn encrypt_decrypt_minimize_memory() { let data = std::iter::repeat("abcdefg").take(10000).collect::(); let mut cursor = Cursor::new(data.clone()); let mut encryptor = AttachmentEncryptor::new(&mut cursor); let mut encrypted = Vec::new(); encryptor.read_to_end(&mut encrypted).unwrap(); let key = encryptor.finish(); assert_ne!(encrypted.as_slice(), data.as_bytes()); let mut cursor = Cursor::new(encrypted); let mut decryptor = AttachmentDecryptor::new(&mut cursor, key).unwrap(); let mut decrypted_data = Vec::new(); decryptor.read_to_end(&mut decrypted_data).unwrap(); assert_eq!( decrypted_data.len(), decrypted_data.capacity(), "{} bytes wasted by decrypted_data", decrypted_data.capacity() - decrypted_data.len() ); } ``` errors with: ``` assertion `left == right` failed: 61072 bytes wasted by decrypted_data left: 70000 right: 131072 ``` By initially setting this capacity, the vector should be slightly larger than needed from the start, avoiding both copying and leftover capacity after decryption is done. --- crates/matrix-sdk/src/media.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/matrix-sdk/src/media.rs b/crates/matrix-sdk/src/media.rs index a5857947f..7f676d1ca 100644 --- a/crates/matrix-sdk/src/media.rs +++ b/crates/matrix-sdk/src/media.rs @@ -278,13 +278,17 @@ impl Media { #[cfg(feature = "e2e-encryption")] let content = { + let content_len = content.len(); let mut cursor = std::io::Cursor::new(content); let mut reader = matrix_sdk_base::crypto::AttachmentDecryptor::new( &mut cursor, file.as_ref().clone().into(), )?; - let mut decrypted = Vec::new(); + // Encrypted size should be the same as the decrypted size, + // rounded up to a cipher block. + let mut decrypted = Vec::with_capacity(content_len); + reader.read_to_end(&mut decrypted)?; decrypted