Fix overflow, race condition, and format bugs

This commit is contained in:
2026-03-07 22:14:48 +02:00
parent 150d483fbe
commit f471d22767
18 changed files with 600 additions and 113 deletions

View File

@@ -94,7 +94,7 @@ fn find_system_font(family: Option<&str>) -> Result<Vec<u8>> {
.to_lowercase();
if file_name.contains(&name_lower)
&& (file_name.ends_with(".ttf") || file_name.ends_with(".otf"))
&& (file_name.contains("regular") || !file_name.contains("bold") && !file_name.contains("italic"))
&& (file_name.contains("regular") || (!file_name.contains("bold") && !file_name.contains("italic")))
{
if let Ok(data) = std::fs::read(&path) {
return Ok(data);
@@ -136,24 +136,27 @@ fn walkdir(dir: &std::path::Path) -> std::io::Result<Vec<std::path::PathBuf>> {
fn walkdir_depth(dir: &std::path::Path, max_depth: u32) -> std::io::Result<Vec<std::path::PathBuf>> {
const MAX_RESULTS: usize = 10_000;
let mut results = Vec::new();
if max_depth == 0 || !dir.is_dir() {
return Ok(results);
walkdir_depth_inner(dir, max_depth, &mut results, MAX_RESULTS);
Ok(results)
}
fn walkdir_depth_inner(dir: &std::path::Path, max_depth: u32, results: &mut Vec<std::path::PathBuf>, max: usize) {
if max_depth == 0 || !dir.is_dir() || results.len() >= max {
return;
}
for entry in std::fs::read_dir(dir)? {
if results.len() >= MAX_RESULTS {
let Ok(entries) = std::fs::read_dir(dir) else { return };
for entry in entries {
if results.len() >= max {
break;
}
let entry = entry?;
let Ok(entry) = entry else { continue };
let path = entry.path();
if path.is_dir() {
if let Ok(sub) = walkdir_depth(&path, max_depth - 1) {
results.extend(sub);
}
walkdir_depth_inner(&path, max_depth - 1, results, max);
} else {
results.push(path);
}
}
Ok(results)
}
/// Render text onto a transparent RGBA buffer and return it as a DynamicImage
@@ -333,7 +336,7 @@ fn apply_tiled_text_watermark(
let alpha = (opacity * 255.0).clamp(0.0, 255.0) as u8;
let draw_color = Rgba([color[0], color[1], color[2], alpha]);
let text_width = ((text.len().min(10_000) as f32 * font_size.min(1000.0) * 0.6) as i64 + 4).min(8192);
let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 0.6) as i64 + 4).min(8192);
let text_height = ((font_size.min(1000.0) * 1.4) as i64 + 4).min(4096);
let mut y = spacing as i64;
@@ -363,8 +366,9 @@ fn apply_tiled_image_watermark(
reason: format!("Failed to load watermark image: {}", e),
})?;
let wm_width = ((watermark.width() as f32 * scale) as u32).clamp(1, 16384);
let wm_height = ((watermark.height() as f32 * scale) as u32).clamp(1, 16384);
let safe_scale = if scale.is_finite() && scale > 0.0 { scale } else { 1.0 };
let wm_width = ((watermark.width() as f32 * safe_scale) as u32).clamp(1, 16384);
let wm_height = ((watermark.height() as f32 * safe_scale) as u32).clamp(1, 16384);
let mut watermark = watermark.resize_exact(wm_width, wm_height, image::imageops::FilterType::Lanczos3);
if let Some(rot) = rotation {
@@ -426,8 +430,9 @@ fn apply_image_watermark(
})?;
// Scale the watermark (capped to prevent OOM on extreme scale values)
let wm_width = ((watermark.width() as f32 * scale) as u32).clamp(1, 16384);
let wm_height = ((watermark.height() as f32 * scale) as u32).clamp(1, 16384);
let safe_scale = if scale.is_finite() && scale > 0.0 { scale } else { 1.0 };
let wm_width = ((watermark.width() as f32 * safe_scale) as u32).clamp(1, 16384);
let wm_height = ((watermark.height() as f32 * safe_scale) as u32).clamp(1, 16384);
let mut watermark = watermark.resize_exact(
wm_width,