Fix quadratic PostScript search in the EPS importer

Fixes #3582

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-24 01:43:54 +07:00
committed by bflatastic
co-authored by Claude Haiku 5.5
parent abe277462b
commit 3867e87036
6 changed files with 16 additions and 1 deletions
Generated
+1
View File
@@ -4767,6 +4767,7 @@ dependencies = [
"hayro-ccitt",
"image",
"kurbo 0.13.1",
"memchr",
"ruzstd",
"serde_json",
"vectorcraft-brush",
+2
View File
@@ -91,6 +91,8 @@ ruzstd = { version = "0.9.1", default-features = false, features = ["std"] }
# CCITT Group 3 and Group 4 decoder (ITU-T T.4 and T.6): EPS images read through
# `CCITTFaxDecode`. The PDF reader's hayro-syntax uses the same version.
hayro-ccitt = "0.3"
# Substring search for the EPS reader's PostScript `search`.
memchr = "2"
jpeg-encoder = { version = "0.6", default-features = false, features = ["std"] }
gif = { version = "0.14", default-features = false, features = ["std", "raii_no_panic"] }
# CMYK image samples (vectorcraft-doc's cmyk module): the image crate's own TIFF and JPEG
+2
View File
@@ -29,6 +29,8 @@ ruzstd = { workspace = true }
hayro-ccitt = { workspace = true }
# Live effects' params, as the art styles that name them give them.
serde_json = { workspace = true }
# Substring search for PostScript `search`.
memchr = { workspace = true }
[dev-dependencies]
vectorcraft-testkit = { workspace = true }
+1
View File
@@ -951,6 +951,7 @@ impl<'a> Interp<'a> {
let seek = self.pop_str()?.to_vec();
let s = self.pop_str()?;
let text = s.to_vec();
self.spend((text.len() / 64) as u64)?;
let at = if op == Search { super::lex::find(&text, &seek) } else { text.starts_with(&seek).then_some(0) };
match at {
Some(i) => {
+1 -1
View File
@@ -252,7 +252,7 @@ pub(crate) fn find(hay: &[u8], needle: &[u8]) -> Option<usize> {
if needle.is_empty() {
return Some(0);
}
hay.windows(needle.len()).position(|w| w == needle)
memchr::memmem::find(hay, needle)
}
/// Hexadecimal digits (whitespace ignored, an odd last digit padded with 0); `None` on others.
+9
View File
@@ -1122,3 +1122,12 @@ fn a_damaged_palette_preview_is_refused_without_panicking() {
assert!(e.contains("can't be read"), "{e}");
}
}
/// #3582: `search` in a loop on multi-megabyte strings, with a needle half as
/// long as the string that differs in its last byte, finish quickly and run out of the operation
/// budget.
#[test]
fn search_in_a_loop_runs_out_of_the_budget() {
let make = "/h 4194304 string def /n 2097152 string def n 2097152 1 sub 1 put";
runs_out_of_budget(&format!("{make} {{ h n search {{ pop pop pop }} {{ pop }} ifelse }} loop"));
}