Fix for 686994 (dangling pdf14 pointers)

Raph Levien <[email protected]>
Newsgroups gmane.comp.printing.ghostscript.patches
Message-ID <[email protected]>
Fixes two pointers to freed objects that were left dangling
in the PDF 1.4 transparency logic. Fixes bug #686994.

DETAILS:

With some test files, saved graphics states had held on to pointers to
the device filter stack that had already been freed by a
gs_pop_device_filter() call. These dangling pointers can cause garbage
collection corruption. This patch introduces reference counting
discipline to these pointers so that the dfilter_stack objects are not
actually freed until the last reference is dropped.

A similar but simpler argument applies to the pdf14_ctx object in the
pdf14_device. This patch simply sets the pointer to NULL when freeing
the context.

---

I am committing this patch now so that we can see the results of
tonight's regression run. Test file ai2.pdf now runs correctly.

Raph

Index: src/gdevp14.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevp14.c,v
retrieving revision 1.18
diff -C2 -r1.18 gdevp14.c
*** src/gdevp14.c	23 Jul 2003 21:27:48 -0000	1.18
--- src/gdevp14.c	15 Aug 2003 22:13:29 -0000
***************
*** 933,938 ****
      pdf14_device *pdev = (pdf14_device *)dev;
  
!     if (pdev->ctx)
  	pdf14_ctx_free(pdev->ctx);
      return 0;
  }
--- 933,940 ----
      pdf14_device *pdev = (pdf14_device *)dev;
  
!     if (pdev->ctx) {
  	pdf14_ctx_free(pdev->ctx);
+ 	pdev->ctx = NULL;
+     }
      return 0;
  }
Index: src/gsstate.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsstate.c,v
retrieving revision 1.20
diff -C2 -r1.20 gsstate.c
*** src/gsstate.c	17 Jun 2003 09:42:19 -0000	1.20
--- src/gsstate.c	15 Aug 2003 22:20:34 -0000
***************
*** 322,325 ****
--- 322,326 ----
       */
      pnew->clip_stack = 0;
+     rc_increment(pnew->dfilter_stack);
      pgs->saved = pnew;
      if (pgs->show_gstate == pgs)
***************
*** 479,482 ****
--- 480,484 ----
      pnew = gstate_clone(pgs, mem, "gs_gstate", copy_for_gstate);
      rc_increment(pnew->clip_stack);
+     rc_increment(pnew->dfilter_stack);
      pgs->view_clip = view_clip;
      if (pnew == 0)
***************
*** 926,929 ****
--- 928,932 ----
      rc_decrement(pgs->device, cname);
      rc_decrement(pgs->clip_stack, cname);
+     rc_decrement(pgs->dfilter_stack, cname);
      cs_adjust_counts(pgs, -1);
      if (pgs->client_data != 0)
***************
*** 982,985 ****
--- 985,989 ----
      RCCOPY(device);
      RCCOPY(clip_stack);
+     RCCOPY(dfilter_stack);
      {
  	struct gx_pattern_cache_s *pcache = pto->pattern_cache;
Index: src/gsdfilt.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsdfilt.c,v
retrieving revision 1.7
diff -C2 -r1.7 gsdfilt.c
*** src/gsdfilt.c	7 Oct 2002 08:28:56 -0000	1.7
--- src/gsdfilt.c	15 Aug 2003 22:20:34 -0000
***************
*** 41,50 ****
  #include "gsdfilt.h"
  
- struct gs_device_filter_stack_s {
-     gs_device_filter_stack_t *next;
-     gs_device_filter_t *df;
-     gx_device *next_device;
- };
- 
  gs_private_st_ptrs3(st_gs_device_filter_stack, gs_device_filter_stack_t,
  		    "gs_device_filter_stack",
--- 41,44 ----
***************
*** 77,80 ****
--- 71,75 ----
      pgs->dfilter_stack = dfs;
      dfs->df = df;
+     rc_init(dfs, mem, 1);
      gs_setdevice_no_init(pgs, new_dev);
      rc_decrement_only(new_dev, "gs_push_device_filter");
***************
*** 98,102 ****
      gs_setdevice_no_init(pgs, dfs_tos->next_device);
      rc_decrement_only(dfs_tos->next_device, "gs_pop_device_filter");
!     gs_free_object(mem, dfs_tos, "gs_pop_device_filter");
      code = df->postpop(df, mem, pgs, tos_device);
      rc_decrement_only(tos_device, "gs_pop_device_filter");
--- 93,98 ----
      gs_setdevice_no_init(pgs, dfs_tos->next_device);
      rc_decrement_only(dfs_tos->next_device, "gs_pop_device_filter");
!     dfs_tos->df = NULL;
!     rc_decrement_only(dfs_tos, "gs_pop_device_filter");
      code = df->postpop(df, mem, pgs, tos_device);
      rc_decrement_only(tos_device, "gs_pop_device_filter");
Index: src/gsdfilt.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gsdfilt.h,v
retrieving revision 1.8
diff -C2 -r1.8 gsdfilt.h
*** src/gsdfilt.h	8 Oct 2002 23:02:31 -0000	1.8
--- src/gsdfilt.h	15 Aug 2003 22:20:34 -0000
***************
*** 37,42 ****
  #endif
  
! /* This is the base structure from which device filters are derived. */
  typedef struct gs_device_filter_s gs_device_filter_t;
  
  struct gs_device_filter_s {
--- 37,44 ----
  #endif
  
! #ifndef gs_device_filter_DEFINED
! #  define gs_device_filter_DEFINED
  typedef struct gs_device_filter_s gs_device_filter_t;
+ #endif
  
  struct gs_device_filter_s {
Index: src/gzstate.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gzstate.h,v
retrieving revision 1.8
diff -C2 -r1.8 gzstate.h
*** src/gzstate.h	22 Aug 2002 07:12:29 -0000	1.8
--- src/gzstate.h	15 Aug 2003 22:20:34 -0000
***************
*** 63,66 ****
--- 63,84 ----
  #endif
  
+ /* Device filter stack structure is defined here so that gstate
+    lifecycle operations can access reference count; implementation is
+    in gsdfilt.c.
+  */
+ 
+ #ifndef gs_device_filter_DEFINED
+ #  define gs_device_filter_DEFINED
+ typedef struct gs_device_filter_s gs_device_filter_t;
+ #endif
+ 
+ /* This is the base structure from which device filters are derived. */
+ struct gs_device_filter_stack_s {
+     gs_device_filter_stack_t *next;
+     gs_device_filter_t *df;
+     gx_device *next_device;
+     rc_header rc;
+ };
+ 
  /* Graphics state structure. */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.