From 2b71a83c0b365c4377717feb405658b60d1dec48 Mon Sep 17 00:00:00 2001 From: Matteo Paonessa Date: Sat, 8 Apr 2023 13:22:11 +0200 Subject: [PATCH] Fixing jpeg memory leak --- Cargo.toml | 10 ++++----- src/jpeg.rs | 61 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9f19a58..521ce72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libcaesium" -version = "0.11.0" +version = "0.11.1" authors = ["Matteo Paonessa "] edition = "2021" categories = ["multimedia::images"] @@ -22,17 +22,17 @@ repository = "https://github.com/Lymphatus/libcaesium" license = "Apache-2.0" [dependencies] -mozjpeg-sys = { version = "1.0.2", optional = true } -oxipng = { version = "8.0.0", optional = true } +mozjpeg-sys = { version = "1.0", optional = true } +oxipng = { version = "8.0", optional = true } libc = "0.2" gifsicle = { version = "1.92.5", optional = true } webp = { version = "0.2", optional = true } -infer = "0.12.0" +infer = "0.13.0" image = { version = "0.24.3", default-features = false, features = ["jpeg", "png", "webp", "gif"] } img-parts = "0.3" bytes = "1.1" lodepng = { version = "3.7", optional = true } -imagequant = {git = "https://github.com/Lymphatus/libimagequant", rev = "67f1686", optional = true} +imagequant = {version = "4.1", optional = true} [features] default = ["jpg", "png", "webp", "gif"] diff --git a/src/jpeg.rs b/src/jpeg.rs index 883149b..87949ea 100644 --- a/src/jpeg.rs +++ b/src/jpeg.rs @@ -2,10 +2,11 @@ use image::ImageOutputFormat::Jpeg; use img_parts::{DynImage, ImageEXIF, ImageICC}; use mozjpeg_sys::*; -use std::fs; +use std::{fs, ptr}; use std::fs::File; use std::io::Write; use std::{io, mem}; +use libc::free; use crate::resize::resize; use crate::CSParameters; @@ -36,23 +37,20 @@ pub fn compress_to_memory(mut in_file: Vec, parameters: &CSParameters) -> Re } unsafe { - let compression_buffer: (*mut u8, u64) = if parameters.optimize { + let compression_buffer = if parameters.optimize { lossless(in_file, parameters)? } else { lossy(in_file, parameters)? }; - let slice = std::slice::from_raw_parts( - compression_buffer.0, - compression_buffer.1 as usize, - ); - Ok(slice.to_vec()) + + Ok(compression_buffer) } } unsafe fn lossless( in_file: Vec, parameters: &CSParameters, -) -> Result<(*mut u8, u64), io::Error> { +) -> Result, io::Error> { let mut src_info: jpeg_decompress_struct = mem::zeroed(); let mut src_err = mem::zeroed(); @@ -80,7 +78,7 @@ unsafe fn lossless( let dst_coef_arrays = src_coef_arrays; dst_info.optimize_coding = i32::from(true); - let mut buf = std::ptr::null_mut(); + let mut buf = ptr::null_mut(); let mut buf_size = 0; jpeg_mem_dest(&mut dst_info, &mut buf, &mut buf_size); jpeg_write_coefficients(&mut dst_info, dst_coef_arrays); @@ -104,10 +102,19 @@ unsafe fn lossless( jpeg_finish_decompress(&mut src_info); jpeg_destroy_decompress(&mut src_info); - Ok((buf, buf_size as u64)) + let slice = std::slice::from_raw_parts( + buf, + buf_size as usize, + ); + + let result = slice.to_vec(); + + free(buf as *mut c_void); + + Ok(result) } -unsafe fn lossy(in_file: Vec, parameters: &CSParameters) -> Result<(*mut u8, u64), io::Error> { +unsafe fn lossy(in_file: Vec, parameters: &CSParameters) -> Result, io::Error> { let mut src_info: jpeg_decompress_struct = mem::zeroed(); let mut src_err = mem::zeroed(); let mut dst_info: jpeg_compress_struct = mem::zeroed(); @@ -129,9 +136,6 @@ unsafe fn lossy(in_file: Vec, parameters: &CSParameters) -> Result<(*mut u8, } jpeg_read_header(&mut src_info, true as boolean); - let mut buf = std::ptr::null_mut(); - let mut buf_size = 0; - jpeg_mem_dest(&mut dst_info, &mut buf, &mut buf_size); let width = src_info.image_width; let height = src_info.image_height; @@ -149,9 +153,6 @@ unsafe fn lossy(in_file: Vec, parameters: &CSParameters) -> Result<(*mut u8, jpeg_read_scanlines(&mut src_info, jsamparray.as_mut_ptr(), 1); } - dst_info.image_width = width; - dst_info.image_height = height; - dst_info.in_color_space = color_space; let input_components = match color_space { JCS_GRAYSCALE => 1, JCS_RGB => 3, @@ -160,7 +161,14 @@ unsafe fn lossy(in_file: Vec, parameters: &CSParameters) -> Result<(*mut u8, JCS_YCCK => 4, _ => 3, }; - dst_info.input_components = input_components; + let mut buf_size = 0; + let mut buf = mem::zeroed(); + jpeg_mem_dest(&mut dst_info, &mut buf, &mut buf_size); + + dst_info.image_width = width; + dst_info.image_height = height; + dst_info.in_color_space = color_space; + dst_info.input_components = input_components as c_int; jpeg_set_defaults(&mut dst_info); let row_stride = dst_info.image_width as usize * dst_info.input_components as usize; @@ -194,14 +202,21 @@ unsafe fn lossy(in_file: Vec, parameters: &CSParameters) -> Result<(*mut u8, jpeg_write_scanlines(&mut dst_info, jsamparray.as_ptr(), 1); } - jpeg_finish_compress(&mut dst_info); - jpeg_destroy_compress(&mut dst_info); jpeg_finish_decompress(&mut src_info); jpeg_destroy_decompress(&mut src_info); + jpeg_finish_compress(&mut dst_info); + jpeg_destroy_compress(&mut dst_info); - // let mut output_file_buffer = File::create(output_path)?; - // output_file_buffer.write_all(std::slice::from_raw_parts(buf, buf_size as usize))?; - Ok((buf, buf_size as u64)) + let slice = std::slice::from_raw_parts( + buf, + buf_size as usize, + ); + + let result = slice.to_vec(); + + free(buf as *mut c_void); + + Ok(result) } fn extract_metadata(image: Vec) -> (Option, Option) {