summaryrefslogtreecommitdiff
path: root/pcl
diff options
context:
space:
mode:
authorRobin Watts <Robin.Watts@artifex.com>2022-01-13 15:39:38 +0000
committerRobin Watts <Robin.Watts@artifex.com>2022-01-13 23:50:14 +0000
commit9c4eb789379cfd0902a4e4981d101d11fc7b01a4 (patch)
tree2c24eca1ddf75d895457e7534bbc749e00f18527 /pcl
parent77a0642a5a3b07f864109e1d1b2718403e7e2ae3 (diff)
downloadghostpdl-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.c33
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 */