diff --git a/crates/fonts/src/fontdb.rs b/crates/fonts/src/fontdb.rs index 840284690..973c7427d 100644 --- a/crates/fonts/src/fontdb.rs +++ b/crates/fonts/src/fontdb.rs @@ -194,13 +194,13 @@ impl FontFace { self.location(), HintingOptions { engine: Engine::Interpreter, target: Target::Mono }, ) - .map_err(|e| log::warn!("Cannot initialize outline interpreter for {}: {e}", self.family)) + .map_err(|e| log::warn!("Cannot initialize outline interpreter for {:?}: {e}", self.family)) .ok() }); let settings = hinter.as_ref().map_or_else(|| DrawSettings::unhinted(Size::unscaled(), self.location()), |h| DrawSettings::hinted(h, false)); if let Err(e) = g.draw(settings, &mut pen) { - log::warn!("Cannot draw glyph {gid} in {}: {e}", self.family); + log::warn!("Cannot draw glyph {gid} in {:?}: {e}", self.family); return BezPath::new(); } } diff --git a/crates/fonts/src/fontdb/user.rs b/crates/fonts/src/fontdb/user.rs index 7e0ead7ed..09bbf8470 100644 --- a/crates/fonts/src/fontdb/user.rs +++ b/crates/fonts/src/fontdb/user.rs @@ -366,7 +366,8 @@ impl FontDb { None } Err(e) => { - log::warn!("couldn't store the font {name} in {}: {e}", dir.display()); + // Debug-quoted: a line break in the supplied name must not start a forged log record. + log::warn!("couldn't store the font {name:?} in {}: {e}", dir.display()); Some(format!("added for this session only: couldn't store it in {}: {e}", dir.display())) } }, @@ -903,6 +904,44 @@ pub(crate) mod tests { let _ = std::fs::remove_dir_all(&dir); } + /// The messages logged while this test binary runs. + fn logged() -> &'static std::sync::Mutex> { + static LOG: std::sync::OnceLock>> = std::sync::OnceLock::new(); + struct Capture; + impl log::Log for Capture { + fn enabled(&self, _: &log::Metadata) -> bool { + true + } + fn log(&self, r: &log::Record) { + if let Some(l) = LOG.get() { + l.lock().unwrap().push(r.args().to_string()); + } + } + fn flush(&self) {} + } + LOG.get_or_init(|| { + let _ = log::set_logger(&Capture); + log::set_max_level(log::LevelFilter::Warn); + std::sync::Mutex::new(Vec::new()) + }) + } + + #[test] + fn a_supplied_name_is_logged_escaped() { + // #3692: a line break in the name must not start a forged record in the log file. + let log = logged(); + let not_a_folder = temp_dir("not-a-folder"); + std::fs::write(¬_a_folder, b"x").unwrap(); + let db = db(); + db.load_user_fonts(¬_a_folder); + let r = db.install_font("a\nERROR forged record.ttf", &renamed("SourceSans3-Regular.ttf", FAMILY)).unwrap(); + assert!(r.warning.is_some(), "the font can't be stored"); + let lines = log.lock().unwrap(); + let line = lines.iter().find(|l| l.contains("forged record")).unwrap(); + assert!(!line.contains('\n'), "{line}"); + let _ = std::fs::remove_file(¬_a_folder); + } + #[test] fn stored_names_are_safe_and_unique() { let ttf = renamed("SourceSans3-Regular.ttf", FAMILY);