mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #3822 from Silvertree2010/fix/3593-audit-eps-import-gstate-currentg
Charge gstate and currentgstate path copies to the memory budget
This commit is contained in:
@@ -1330,11 +1330,13 @@ impl Interp<'_> {
|
||||
}
|
||||
GStateNew => {
|
||||
self.spend_elements(self.g.path.elements().len())?;
|
||||
self.alloc(std::mem::size_of_val(self.g.path.elements()))?;
|
||||
self.push(Obj::GState(Rc::new(self.g.clone())))?;
|
||||
}
|
||||
CurrentGState => {
|
||||
self.pop()?;
|
||||
self.spend_elements(self.g.path.elements().len())?;
|
||||
self.alloc(std::mem::size_of_val(self.g.path.elements()))?;
|
||||
self.push(Obj::GState(Rc::new(self.g.clone())))?;
|
||||
}
|
||||
SetGState => match self.pop()? {
|
||||
|
||||
@@ -899,7 +899,7 @@ fn paths_made_in_a_loop_run_out_of_the_budget() {
|
||||
/// A loop of operators that read or copy the whole current path or clip path runs out of the
|
||||
/// operation budget (PLRM 3rd ed., chapter 8): `pathbbox`, `clip`, `clippath`, `shfill` (which
|
||||
/// reads the clip path for the area it paints), `pathforall` (which copies the path before it runs
|
||||
/// a procedure), `gstate`, `currentgstate` and `setgstate`.
|
||||
/// a procedure) and `setgstate`. `gstate` and `currentgstate` run out of memory first.
|
||||
#[test]
|
||||
fn paths_read_or_copied_in_a_loop_run_out_of_the_budget() {
|
||||
// 10,001 elements reaching 10,000,000 points to the right: what `shfill` paints in a clip of
|
||||
@@ -913,8 +913,6 @@ fn paths_read_or_copied_in_a_loop_run_out_of_the_budget() {
|
||||
"clip newpath { clippath } loop",
|
||||
"clip newpath { sh shfill } loop",
|
||||
"{ { pop pop exit } { } { } { } pathforall } loop",
|
||||
"{ gstate pop } loop",
|
||||
"/g gstate def { g currentgstate pop } loop",
|
||||
"/g gstate def { g setgstate } loop",
|
||||
] {
|
||||
runs_out_of_budget(&format!("{sh} {path} {body}"));
|
||||
@@ -1162,3 +1160,14 @@ fn an_oversized_image_plane_is_refused() {
|
||||
.unwrap_err();
|
||||
assert!(e.contains("too large"), "{e}");
|
||||
}
|
||||
|
||||
/// Graphics states kept with `gstate` or `currentgstate` each hold a copy of the current path, and
|
||||
/// the copies count against the memory budget as `gsave` does.
|
||||
#[test]
|
||||
fn stored_graphics_states_use_up_the_memory_budget() {
|
||||
let path = "newpath 0 0 moveto 0 1 1000000 { pop 1 0 rlineto } for";
|
||||
for body in ["30 { gstate } repeat", "30 { 0 currentgstate } repeat"] {
|
||||
let r = read_soon(&format!("0 0 10 10 rectfill {path} {body}"));
|
||||
assert!(r.warnings.iter().any(|w| w.contains("uses too much memory")), "{body}: {:?}", r.warnings);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user