Charge and bound EPS image sample planes on import

Squashed from #3821 onto main.
This commit is contained in:
bflatastic
2026-10-24 01:43:55 +07:00
parent 0b6097e572
commit 246750c147
2 changed files with 36 additions and 0 deletions
+5
View File
@@ -1093,6 +1093,11 @@ impl Interp<'_> {
let row = row_bits.div_ceil(8);
// Several sources are read in turn, a row at a time each (zeros past their ends).
let sources = if multi { &s.sources[..] } else { s.sources.get(..1).ok_or(PsError::Ps("undefined", "DataSource".into()))? };
if sources.len() > n {
return ps_err("rangecheck", "DataSource");
}
let plane = row.checked_mul(s.h).filter(|p| *p <= MAX_DATA).ok_or(PsError::Limit("decoded data is too large"))?;
self.alloc(plane.saturating_mul(sources.len()))?;
let mut planes = self.read_sources(sources, row * s.h, if multi { row } else { row * s.h })?;
for p in &mut planes {
p.resize(row * s.h, 0);
+31
View File
@@ -1131,3 +1131,34 @@ 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"));
}
/// #3568: an image dictionary with more data sources than colour components is a `rangecheck`.
#[test]
fn an_image_with_more_data_sources_than_components_is_refused() {
let sources = "<80> ".repeat(64);
let e = import(&eps(&format!(
"/DeviceGray setcolorspace << /ImageType 1 /Width 64 /Height 64 /BitsPerComponent 8 /MultipleDataSources true \
/ImageMatrix [64 0 0 64 0 0] /DataSource [{sources}] >> image"
)))
.unwrap_err();
assert!(e.contains("rangecheck") && e.contains("DataSource"), "{e}");
}
/// #3568: every data source's plane is charged against the memory budget, not only the RGBA
/// output: two large four-source images together go over it.
#[test]
fn the_planes_of_multi_source_images_are_charged() {
let image = "/DeviceCMYK setcolorspace << /ImageType 1 /Width 8192 /Height 8192 /BitsPerComponent 8 \
/MultipleDataSources true /ImageMatrix [8192 0 0 8192 0 0] /DataSource [<80> <80> <80> <80>] >> image\n";
let r = import(&eps(&image.repeat(2))).unwrap();
assert!(r.warnings.iter().any(|w| w.contains("too much memory")), "{:?}", r.warnings);
}
/// #3568: a single sample plane over the data limit is refused.
#[test]
fn an_oversized_image_plane_is_refused() {
let e = import(&eps("/DeviceCMYK setcolorspace << /ImageType 1 /Width 8192 /Height 8192 /BitsPerComponent 16 \
/ImageMatrix [8192 0 0 8192 0 0] /DataSource <80> >> image"))
.unwrap_err();
assert!(e.contains("too large"), "{e}");
}