diff options
author | Robin Watts <Robin.Watts@artifex.com> | 2022-01-13 15:39:38 +0000 |
---|---|---|
committer | Robin Watts <Robin.Watts@artifex.com> | 2022-01-13 23:50:14 +0000 |
commit | 9c4eb789379cfd0902a4e4981d101d11fc7b01a4 (patch) | |
tree | 2c24eca1ddf75d895457e7534bbc749e00f18527 /pcl | |
parent | 77a0642a5a3b07f864109e1d1b2718403e7e2ae3 (diff) | |
download | ghostpdl-9c4eb789379cfd0902a4e4981d101d11fc7b01a4.tar.gz |
Fix PCL interpreter leaking a graphics state.
A memento build of pcl, run with no arguments shows significant
leakage. Part of this is due to a graphics state leaking from the
PCL interpreter.
This appears to be because of unexpected (to me at least!) behaviour
with gsave/grestore. If we make a graphics state, and then gsave,
we might reasonably expect grestore to leave us back in the newly
created state.
This is not the case; when grestore restores, if it would leave us
back at the 'topmost' gstate, it does an extra gsave. This is
believed to be to do with coping with Postscript files that have
more grestores than gsaves.
Accordingly, we work around it here by doing an extra gs_gsave at
the start, and an extra gs_restore_only at the end.
This solves at least some of the leaks.
Diffstat (limited to 'pcl')
-rw-r--r-- | pcl/pcl/pctop.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/pcl/pcl/pctop.c b/pcl/pcl/pctop.c index 16c93f3a3..f9f16a577 100644 --- a/pcl/pcl/pctop.c +++ b/pcl/pcl/pctop.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2021 Artifex Software, Inc. +/* Copyright (C) 2001-2022 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or @@ -221,6 +221,7 @@ pcl_impl_allocate_interp_instance(pl_interp_implementation_t *impl, gs_memory_t * mem /* allocator to allocate instance from */ ) { + int code; /* Allocate everything up front */ pcl_interp_instance_t *pcli /****** SHOULD HAVE A STRUCT DESCRIPTOR ******/ = (pcl_interp_instance_t *) gs_alloc_bytes(mem, @@ -255,20 +256,26 @@ pcl_impl_allocate_interp_instance(pl_interp_implementation_t *impl, /* Init gstate to point to pcl state */ gs_gstate_set_client(pgs, &pcli->pcs, &pcl_gstate_procs, true); /* register commands */ - { - int code = pcl_do_registrations(&pcli->pcs, &pcli->pst); - - if (code < 0) { - if (pcli->pcs.pids != NULL) - gs_free_object(mem, pcli->pcs.pids, "PCL gsave"); - gs_gstate_free(pgs); - gs_free_object(mem, pcli, "pcl_allocate_interp_instance(pcl_interp_instance_t)"); - return (code); - } + code = pcl_do_registrations(&pcli->pcs, &pcli->pst); + if (code < 0) { + if (pcli->pcs.pids != NULL) + gs_free_object(mem, pcli->pcs.pids, "PCL gsave"); + gs_gstate_free(pgs); + gs_free_object(mem, pcli, "pcl_allocate_interp_instance(pcl_interp_instance_t)"); + return (code); } pcli->pcs.pjls = pl_main_get_pjl_instance(mem); + /* Perform a gsave. This is to ensure that any grestores done + * in the operation of the device never restore to the topmost + * gstate. gs_grestore doesn't like that, and if asked to do so + * it does another gsave. This leaves us off by one in the + * counting which causes leaks. */ + code = gs_gsave(pcli->pcs.pgs); + if (code < 0) + return code; + /* Return success */ impl->interp_client_data = pcli; /* Initial reset for the PCL interpreter */ @@ -552,6 +559,10 @@ pcl_impl_deallocate_interp_instance(pl_interp_implementation_t * impl /* ins /* free default, pdflt_* objects */ pcl_free_default_objects(mem, &pcli->pcs); + /* Restore the gstate once, to match the extra 'gsave' done in + * pcl_impl_allocate_interp_instance. */ + gs_grestore_only(pcli->pcs.pgs); + /* free halftone cache in gs state */ gs_gstate_free(pcli->pcs.pgs); /* remove pcl's gsave grestore stack */ |