diff options
author | Ken Sharp <ken.sharp@artifex.com> | 2012-04-19 16:44:48 +0100 |
---|---|---|
committer | Ken Sharp <ken.sharp@artifex.com> | 2012-05-04 11:30:43 +0100 |
commit | 19e1c90a1185b681e081cc50ea64a73e8fd8f9b7 (patch) | |
tree | fa64331c4b3b2d5bccac22846caf502a0280a49a | |
parent | 714b375a58593b62a38c3fa5dfacd0fae2d7d1f9 (diff) |
pdfwrite - address memory leaks
First pass at cleaning up pdfwrite's memory 'management'.
Add clean up code in pdf_close for fonts, font descriptors, type 3 CharProc
and Pattern resources.
Since we only need the object number for a reference we now create a new
type of cos object 'reference'. This only contains the object ID so that
we cna write out the reference. We also set the ID to 0 after we write it
as this will allow us to free the object. (id == 0 is a crazy reference
counting thing, it seems)
Free the 'aside' associated with a pattern after releasing it.
free ExtGState resources at close.
There was no code to free CMaps, none at all. Added routines to free regular
CMaps and ToUnicode CMaps, and added code to pdfwrite to call these in order
to actually free CMap resources.
When manufacturing a BaseFont, if we already have a BaseFont name, dispose
of it before assigning a new one. Previously this leaked the string
containing the name.
release font resoruce objects
when freeing a font descriptor, free the object as well as the glyphs
Free copied base font FontName string on close
This is opaque data specific to each font type, so we may need to add
specific cleanup routines, but this is a start.
Secondly, when pdfwrite copeis a font it makes 2 copies, a subset and a
complete copy. However the complete copy can fail because of an unused
glyph. So we dicard the complete copy and carry on with the subset. In
this case we didnt' clean up the 'complete' copy.
Modified the previous code into one routine to free copied fonts, when we
discard a (complete) copied font during font copying free the font copy.
free Encoding from copied fonts if present
Also, change the text for font freeing so it makes sense.
Free copied font 'data' when freeing copied font
Free the 'base_font' structure when freeing FontDescriptors
release colour spaces.
Make a routine to free colour spaces, and have it free the 'serialized'
color space memory.
Free the page dictionary when we free pages.
We seem to have (at least) two different kinds of param lists which are used
to deal with getting/setting device params. The PostScript interpreter uses
'ref_params' and the PCL interpreter uses 'c_params'.
The problem is that 'ref_params_end_write_collection' frees the list memory
but 'c_params_end_write_collection' does not. Since these are accessed through
methods in the list, we don't know whether we need to free the memory or not.
This leads to a memory leak when using the PCL interpreter.
I suspect this is a bug in the implementation, but for now I've modified
'ref_params_end_write_collection' so that it nulls the pointer to the list
when it frees it. The code in gdevdsp.c can then test to see whether the
memory needs to be freed (non-NULL) or not.
For some reason this leads to a Seg Fault with fts_09_0923.pdf, but I
can't see why. I believe this is unrelated, so will investigate it further
after this work is completed.
Also changed a typecast to eliminate a warning
create a routine to clean up the 'text data' and call it. Add the
'standard fonts' to the clenaup in there.
Clean up a number of allocations (name index stack, namespace
stack etc).
Add code to free Funtiocn resource dictionaries, objects and resources,
These were missed previously, because the development was done in PCL and
teh PCL interpreter can't trigger the use of Functions.
Add code to clean up Shading and group dictionary resources. Add code to
clear the resource chains on close so that we don't end up trying to use
freed memory pointers.
-rw-r--r-- | gs/base/gdevpdf.c | 287 | ||||
-rw-r--r-- | gs/base/gdevpdfc.c | 14 | ||||
-rw-r--r-- | gs/base/gdevpdfg.h | 2 | ||||
-rw-r--r-- | gs/base/gdevpdfi.c | 10 | ||||
-rw-r--r-- | gs/base/gdevpdfo.c | 25 | ||||
-rw-r--r-- | gs/base/gdevpdfo.h | 6 | ||||
-rw-r--r-- | gs/base/gdevpdfu.c | 44 | ||||
-rw-r--r-- | gs/base/gdevpdfv.c | 14 | ||||
-rw-r--r-- | gs/base/gdevpdfx.h | 12 | ||||
-rw-r--r-- | gs/base/gdevpdt.c | 11 | ||||
-rw-r--r-- | gs/base/gdevpdt.h | 2 | ||||
-rw-r--r-- | gs/base/gdevpdtb.c | 1 | ||||
-rw-r--r-- | gs/base/gdevpdtd.c | 22 | ||||
-rw-r--r-- | gs/base/gdevpdtd.h | 2 | ||||
-rw-r--r-- | gs/base/gdevpdtf.c | 2 | ||||
-rw-r--r-- | gs/base/gdevpdti.c | 19 | ||||
-rw-r--r-- | gs/base/gdevpdti.h | 2 | ||||
-rw-r--r-- | gs/base/gdevpsdp.c | 4 | ||||
-rw-r--r-- | gs/base/gsfcmap.c | 18 | ||||
-rw-r--r-- | gs/base/gsfcmap.h | 2 | ||||
-rw-r--r-- | gs/base/gxfcmap.h | 2 | ||||
-rw-r--r-- | gs/base/gxfcopy.c | 35 | ||||
-rw-r--r-- | gs/base/gxfcopy.h | 5 | ||||
-rw-r--r-- | gs/psi/iparam.c | 1 |
24 files changed, 521 insertions, 21 deletions
diff --git a/gs/base/gdevpdf.c b/gs/base/gdevpdf.c index 263341ee4..28982f402 100644 --- a/gs/base/gdevpdf.c +++ b/gs/base/gdevpdf.c @@ -27,6 +27,11 @@ #include "smd5.h" #include "sarc4.h" #include "gscms.h" +#include "gdevpdtf.h" +#include "gdevpdtx.h" +#include "gdevpdtd.h" +#include "gdevpdti.h" +#include "gsfcmap.h" /* For gs_cmap_ToUnicode_free */ /* Define the default language level and PDF compatibility level. */ /* Acrobat 4 (PDF 1.3) is the default. */ @@ -1476,9 +1481,262 @@ pdf_close(gx_device * dev) stream_puts(s, ">>\n"); pprintld1(s, "startxref\n%ld\n%%%%EOF\n", xref); } + /* Require special handling for Fonts, ColorSpace and Pattern resources + * These are tracked in pdev->last_resource, and are complex structures which may + * contain other memory allocations. All other resource types can be simply dicarded + * as above. + */ + { + /* PDF font records and all their associated contents need to be + * freed by means other than the garbage collector, or the memory + * usage will increase with languages other than PostScript. In addition + * debug builds of non-PS languages take a long time to close down + * due to reporting the dangling memory allocations. + */ + int j, code = 0; - /* Release the resource records. */ + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdf_resource_t *pres = pdev->resources[resourceFont].chains[j]; + + for (; pres != 0;) { + pdf_font_resource_t *pdfont = (pdf_font_resource_t *)pres; + + if(pdfont->BaseFont.size) { + gs_free_string(pdev->memory, pdfont->BaseFont.data, pdfont->BaseFont.size, "Free BaseFont string"); + pdfont->BaseFont.data = (byte *)0L; + pdfont->BaseFont.size = 0; + } + if(pdfont->Widths) { + gs_free_object(pdev->memory, pdfont->Widths, "Free Widths array"); + pdfont->Widths = 0; + } + if(pdfont->used) { + gs_free_object(pdev->memory, pdfont->used, "Free used array"); + pdfont->used = 0; + } + if(pdfont->res_ToUnicode) { + /* ToUnicode resources are released below */ +/* gs_free_object(pdev->memory, pdfont->res_ToUnicode, "Free ToUnicode resource");*/ + pdfont->res_ToUnicode = 0; + } + if(pdfont->cmap_ToUnicode) { + gs_cmap_ToUnicode_free(pdev->memory, pdfont->cmap_ToUnicode); + pdfont->cmap_ToUnicode = 0; + } + switch(pdfont->FontType) { + case ft_composite: + break; + case ft_PCL_user_defined: + case ft_GL2_stick_user_defined: + case ft_user_defined: + if(pdfont->u.simple.Encoding) { + gs_free_object(pdev->memory, pdfont->u.simple.Encoding, "Free simple Encoding"); + pdfont->u.simple.Encoding = 0; + } + if(pdfont->u.simple.v) { + gs_free_object(pdev->memory, pdfont->u.simple.v, "Free simple v"); + pdfont->u.simple.v = 0; + } + if (pdfont->u.simple.s.type3.char_procs) { + pdf_free_charproc_ownership(pdev, (pdf_resource_t *)pdfont->u.simple.s.type3.char_procs); + pdfont->u.simple.s.type3.char_procs = 0; + } + break; + case ft_CID_encrypted: + case ft_CID_TrueType: + if(pdfont->u.cidfont.used2) { + gs_free_object(pdev->memory, pdfont->u.cidfont.used2, "Free CIDFont used2"); + pdfont->u.cidfont.used2 = 0; + } + if(pdfont->u.cidfont.CIDToGIDMap) { + gs_free_object(pdev->memory, pdfont->u.cidfont.CIDToGIDMap, "Free CIDToGID map"); + pdfont->u.cidfont.CIDToGIDMap = 0; + } + break; + default: + if(pdfont->u.simple.Encoding) { + gs_free_object(pdev->memory, pdfont->u.simple.Encoding, "Free simple Encoding"); + pdfont->u.simple.Encoding = 0; + } + if(pdfont->u.simple.v) { + gs_free_object(pdev->memory, pdfont->u.simple.v, "Free simple v"); + pdfont->u.simple.v = 0; + } + break; + } + if (pdfont->object) { + cos_release(pdfont->object, "release font resource object"); + gs_free_object(pdev->pdf_memory, pdfont->object, "Free font resource object"); + pdfont->object = 0; + } + /* We free FontDescriptor resources separately */ + if(pdfont->FontDescriptor) + pdfont->FontDescriptor = NULL; + pres = pres->next; + } + } + } + + { + int j, code = 0; + + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdf_resource_t *pres = pdev->resources[resourceFontDescriptor].chains[j]; + for (; pres != 0;) { + pdf_font_descriptor_free(pdev, pres); + pres = pres->next; + } + } + } + + { + int j, code = 0; + + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdf_resource_t *pres = pdev->resources[resourceCharProc].chains[j]; + + for (; pres != 0;) { + if (pres->object) { + gs_free_object(pdev->pdf_memory, (byte *)pres->object, "Free CharProc"); + pres->object = 0; + } + pres = pres->next; + } + } + } + + { + int j, code = 0; + + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdf_resource_t *pres = pdev->resources[resourceColorSpace].chains[j]; + for (; pres != 0;) { + free_color_space(pdev, pres); + pres = pres->next; + } + } + } + + { + int j, code = 0; + + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdf_resource_t *pres = pdev->resources[resourceExtGState].chains[j]; + + for (; pres != 0;) { + if (pres->object) { + cos_release(pres->object, "release ExtGState object"); + gs_free_object(pdev->pdf_memory, pres->object, "free ExtGState"); + pres->object = 0; + } + pres = pres->next; + } + } + } + + { + int j, code = 0; + + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdf_resource_t *pres = pdev->resources[resourcePattern].chains[j]; + + for (; pres != 0;) { + if (pres->object) { + cos_release(pres->object, "free pattern dict"); + gs_free_object(pdev->pdf_memory, pres->object, "free pattern resources"); + pres->object = 0; + } + pres = pres->next; + } + } + } + + { + int j, code = 0; + + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdf_resource_t *pres = pdev->resources[resourceShading].chains[j]; + + for (; pres != 0;) { + if (pres->object) { + cos_release(pres->object, "free Shading dict"); + gs_free_object(pdev->pdf_memory, pres->object, "free Shading resources"); + pres->object = 0; + } + pres = pres->next; + } + } + } + + { + int j, code = 0; + + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdf_resource_t *pres = pdev->resources[resourceGroup].chains[j]; + + for (; pres != 0;) { + if (pres->object) { + cos_release(pres->object, "free Group dict"); + gs_free_object(pdev->pdf_memory, pres->object, "free Group resources"); + pres->object = 0; + } + pres = pres->next; + } + } + } + + { + int j, code = 0; + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdf_resource_t *pnext = 0, *pres = pdev->resources[resourceFunction].chains[j]; + + for (; pres != 0;) { + if (pres->object) { + cos_release(pres->object, "free function dict"); + gs_free_object(pdev->pdf_memory, pres->object, "free function resources"); + pres->object = 0; + pnext = pres->next; + gs_free_object(pdev->pdf_memory, pres, "free function"); + } + pres = pnext; + } + } + } + + { + int i, j; + + for (i = 0; i < NUM_RESOURCE_TYPES; i++) { + for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) { + pdev->resources[i].chains[j] = 0; + } + } + } + + /* Release the resource records. */ + /* So what exactly is stored in this list ? I believe the following types of resource: + * + * resourceCharProc + * resourceFont + * resourceCIDFont + * resourceFontDescriptor + * resourceColorSpace + * resourceExtGState + * resourceXObject + * resourceSoftMaskDict + * resourceGroup + * resourcePattern + * resourceShading + * + * resourceCMap resourcePage and resourceFunction don't appear to be tracked. I note + * that resourcePage and resourceCMap are freed above, as is resourceXObject and resourceSoftmaskDict. + * So presumably reourceFunction just leaks. + * + * It seems that all these types of resources are added when they are created + * in addition there are 'pdf_forget_resource' and pdf_cancel_resource which + * remove entries from this list. + */ { pdf_resource_t *pres; pdf_resource_t *prev; @@ -1501,11 +1759,36 @@ pdf_close(gx_device * dev) /* Wrap up. */ + { + int i; + for (i=0;i < pdev->next_page;i++) { + cos_release((cos_object_t *)pdev->pages[i].Page, "Free page dict"); + gs_free_object(mem, pdev->pages[i].Page, "Free Page object"); + } + } gs_free_object(mem, pdev->pages, "pages"); pdev->pages = 0; pdev->num_pages = 0; - if (pdev->ForOPDFRead) { + gs_free_object(mem, pdev->sbstack, "Free sbstack"); + pdev->sbstack = 0; + + text_data_free(mem, pdev->text); + pdev->text = 0; + + cos_release((cos_object_t *)pdev->Pages, "release Pages dict"); + gs_free_object(mem, pdev->Pages, "Free Pages dict"); + pdev->Pages = 0; + + cos_release((cos_object_t *)pdev->NI_stack, "Release Name Index stack"); + gs_free_object(mem, pdev->NI_stack, "Free Name Index stack"); + pdev->NI_stack = 0; + + cos_release((cos_object_t *)pdev->Namespace_stack, "release Name space stack"); + gs_free_object(mem, pdev->Namespace_stack, "Free Name space stack"); + pdev->Namespace_stack = 0; + + { /* pdf_open_dcument could set up filters for entire document. Removing them now. */ int status; diff --git a/gs/base/gdevpdfc.c b/gs/base/gdevpdfc.c index bd75b865e..87c42664d 100644 --- a/gs/base/gdevpdfc.c +++ b/gs/base/gdevpdfc.c @@ -1306,6 +1306,20 @@ pdf_color_space_named(gx_device_pdf *pdev, cos_value_t *pvalue, return 0; } +int free_color_space(gx_device_pdf *pdev, pdf_resource_t *pres) +{ + pdf_color_space_t *ppcs = (pdf_color_space_t *)pres; + + if (ppcs->serialized) + gs_free_object(pdev->pdf_memory, ppcs->serialized, "free serialized colour space"); + if (pres->object) { + cos_release(pres->object, "release ColorSpace object"); + gs_free_object(pdev->pdf_memory, pres->object, "free ColorSpace object"); + pres->object = 0; + } + return 0; +} + /* ---------------- Miscellaneous ---------------- */ /* Create colored and uncolored Pattern color spaces. */ diff --git a/gs/base/gdevpdfg.h b/gs/base/gdevpdfg.h index c94ba9c5b..cecf80ade 100644 --- a/gs/base/gdevpdfg.h +++ b/gs/base/gdevpdfg.h @@ -99,6 +99,8 @@ int pdf_color_space_named(gx_device_pdf *pdev, cos_value_t *pvalue, const pdf_color_space_names_t *pcsn, bool by_name, const byte *res_name, int name_length); +int free_color_space(gx_device_pdf *pdev, pdf_resource_t *pres); + /* Create colored and uncolored Pattern color spaces. */ int pdf_cs_Pattern_colored(gx_device_pdf *pdev, cos_value_t *pvalue); int pdf_cs_Pattern_uncolored(gx_device_pdf *pdev, cos_value_t *pvalue); diff --git a/gs/base/gdevpdfi.c b/gs/base/gdevpdfi.c index 4b84ea4a6..4787e06a0 100644 --- a/gs/base/gdevpdfi.c +++ b/gs/base/gdevpdfi.c @@ -796,6 +796,16 @@ pdf_begin_typed_image_impl(gx_device_pdf *pdev, const gs_imager_state * pis, &pie->writer.binary[1], &image[1].pixel, pmat, pis, false, in_line); if (code == gs_error_rangecheck) { + + for (i=1;i < pie->writer.alt_writer_count; i++) { + stream *s = pie->writer.binary[i].strm; + cos_stream_t *pcos = cos_stream_from_pipeline(pie->writer.binary[i].strm); + s_close_filters(&s, NULL); +// gs_free_object(pdev->pdf_memory, s->cbuf, "compressed image buffer"); + gs_free_object(pdev->pdf_memory, s, "compressed image stream"); + pcos->cos_procs->release((cos_object_t *)pcos, "pdf_begin_typed_image_impl"); + gs_free_object(pdev->pdf_memory, pcos, "compressed image cos_stream"); + } /* setup_image_compression rejected the alternative compression. */ pie->writer.alt_writer_count = 1; memset(pie->writer.binary + 1, 0, sizeof(pie->writer.binary[1])); diff --git a/gs/base/gdevpdfo.c b/gs/base/gdevpdfo.c index 20c3a1d86..be2fae192 100644 --- a/gs/base/gdevpdfo.c +++ b/gs/base/gdevpdfo.c @@ -317,7 +317,7 @@ cos_value_write_spaced(const cos_value_t *pcv, gx_device_pdf *pdev, pprintld1(s, "/R%ld", pcv->contents.object->id); break; case COS_VALUE_OBJECT: { - const cos_object_t *pco = pcv->contents.object; + cos_object_t *pco = pcv->contents.object; if (!pco->id) { if (do_space && @@ -332,6 +332,8 @@ cos_value_write_spaced(const cos_value_t *pcv, gx_device_pdf *pdev, if (do_space) stream_putc(s, ' '); pprintld1(s, "%ld 0 R", pco->id); + if (pco->cos_procs == cos_type_reference) + pco->id = 0; break; } default: /* can't happen */ @@ -397,6 +399,7 @@ static int cos_value_hash(cos_value_t *pcv0, gs_md5_state_t *md5, gs_md5_byte_t /* ------ Generic objects ------ */ +static cos_proc_release(cos_reference_release); static cos_proc_release(cos_generic_release); static cos_proc_write(cos_generic_write); static cos_proc_equal(cos_generic_equal); @@ -404,6 +407,9 @@ static cos_proc_hash(cos_generic_hash); const cos_object_procs_t cos_generic_procs = { cos_generic_release, cos_generic_write, cos_generic_equal, cos_generic_hash }; +const cos_object_procs_t cos_reference_procs = { + cos_reference_release, cos_generic_write, cos_generic_equal, cos_generic_hash +}; cos_object_t * cos_object_alloc(gx_device_pdf *pdev, client_name_t cname) @@ -416,6 +422,23 @@ cos_object_alloc(gx_device_pdf *pdev, client_name_t cname) return pco; } +cos_object_t * +cos_reference_alloc(gx_device_pdf *pdev, client_name_t cname) +{ + gs_memory_t *mem = pdev->pdf_memory; + cos_object_t *pco = + gs_alloc_struct(mem, cos_object_t, &st_cos_object, cname); + + cos_object_init(pco, pdev, &cos_reference_procs); + return pco; +} + +static void +cos_reference_release(cos_object_t *pco, client_name_t cname) +{ + /* Do nothing. */ +} + static void cos_generic_release(cos_object_t *pco, client_name_t cname) { diff --git a/gs/base/gdevpdfo.h b/gs/base/gdevpdfo.h index 98f8c3433..06e238f93 100644 --- a/gs/base/gdevpdfo.h +++ b/gs/base/gdevpdfo.h @@ -135,6 +135,9 @@ cos_object_struct(cos_object_s, cos_element_t); extern const cos_object_procs_t cos_generic_procs; #define cos_type_generic (&cos_generic_procs) +extern const cos_object_procs_t cos_reference_procs; +#define cos_type_reference (&cos_reference_procs) + /* * Define the macro for casting any cos object to type cos_object_t. * Using cos_procs ensures that the argument is, in fact, a cos object. @@ -202,6 +205,9 @@ cos_array_t *cos_array_from_floats(gx_device_pdf *, const float *, uint, cos_dict_t *cos_dict_alloc(gx_device_pdf *, client_name_t); cos_stream_t *cos_stream_alloc(gx_device_pdf *, client_name_t); +/* A 'dummy object, used only to create a reference in a dict when writing */ +cos_object_t *cos_reference_alloc(gx_device_pdf *, client_name_t); + /* Get the allocator for a Cos object. */ gs_memory_t *cos_object_memory(const cos_object_t *); #define COS_OBJECT_MEMORY(pc) cos_object_memory(CONST_COS_OBJECT(pc)) diff --git a/gs/base/gdevpdfu.c b/gs/base/gdevpdfu.c index 2d8564574..77f676935 100644 --- a/gs/base/gdevpdfu.c +++ b/gs/base/gdevpdfu.c @@ -1080,17 +1080,21 @@ const gs_memory_struct_type_t *const pdf_resource_type_structs[] = { int pdf_cancel_resource(gx_device_pdf * pdev, pdf_resource_t *pres, pdf_resource_type_t rtype) { - /* fixme : remove *pres from resource chain. */ + /* fixme : Remove *pres from resource chain. */ pres->where_used = 0; - pres->object->written = true; - if (rtype == resourceXObject || rtype == resourceCharProc || rtype == resourceOther - || rtype > NUM_RESOURCE_TYPES) { - int code = cos_stream_release_pieces((cos_stream_t *)pres->object); + if (pres->object) { + pres->object->written = true; + if (rtype == resourceXObject || rtype == resourceCharProc || rtype == resourceOther + || rtype > NUM_RESOURCE_TYPES) { + int code = cos_stream_release_pieces((cos_stream_t *)pres->object); - if (code < 0) - return code; + if (code < 0) + return code; + } + cos_release(pres->object, "pdf_cancel_resource"); + gs_free_object(pdev->pdf_memory, pres->object, "pdf_cancel_resources"); + pres->object = 0; } - cos_release(pres->object, "pdf_cancel_resource"); return 0; } @@ -1113,8 +1117,11 @@ pdf_forget_resource(gx_device_pdf * pdev, pdf_resource_t *pres1, pdf_resource_ty for (; (pres = *pprev) != 0; pprev = &pres->next) if (pres == pres1) { *pprev = pres->next; - COS_RELEASE(pres->object, "pdf_forget_resource"); - gs_free_object(pdev->pdf_memory, pres->object, "pdf_forget_resource"); + if (pres->object) { + COS_RELEASE(pres->object, "pdf_forget_resource"); + gs_free_object(pdev->pdf_memory, pres->object, "pdf_forget_resource"); + pres->object = 0; + } gs_free_object(pdev->pdf_memory, pres, "pdf_forget_resource"); break; } @@ -1212,7 +1219,7 @@ pdf_find_same_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, pdf_reso int code; cos_object_t *pco1 = pres->object; - if (cos_type(pco0) != cos_type(pco1)) + if (pco1 == NULL || cos_type(pco0) != cos_type(pco1)) continue; /* don't compare different types */ code = pco0->cos_procs->equal(pco0, pco1, pdev); if (code < 0) @@ -1256,8 +1263,11 @@ pdf_drop_resources(gx_device_pdf * pdev, pdf_resource_type_t rtype, for (; (pres = *pprev) != 0; ) if (pres->next == pres) { *pprev = pres->prev; - COS_RELEASE(pres->object, "pdf_drop_resources"); - gs_free_object(pdev->pdf_memory, pres->object, "pdf_drop_resources"); + if (pres->object) { + COS_RELEASE(pres->object, "pdf_drop_resources"); + gs_free_object(pdev->pdf_memory, pres->object, "pdf_drop_resources"); + pres->object = 0; + } gs_free_object(pdev->pdf_memory, pres, "pdf_drop_resources"); } else pprev = &pres->prev; @@ -1457,7 +1467,7 @@ pdf_write_resource_objects(gx_device_pdf *pdev, pdf_resource_type_t rtype) for (; pres != 0; pres = pres->next) if ((!pres->named || pdev->ForOPDFRead) - && !pres->object->written) { + && pres->object && !pres->object->written) { code = cos_write_object(pres->object, pdev, rtype); } } @@ -1507,8 +1517,10 @@ pdf_free_resource_objects(gx_device_pdf *pdev, pdf_resource_type_t rtype) if (pres->named) { /* named, don't free */ prev = &pres->next; } else { - cos_free(pres->object, "pdf_free_resource_objects"); - pres->object = 0; + if (pres->object) { + cos_free(pres->object, "pdf_free_resource_objects"); + pres->object = 0; + } *prev = pres->next; } } diff --git a/gs/base/gdevpdfv.c b/gs/base/gdevpdfv.c index 90d5e0cc3..e26ce7dce 100644 --- a/gs/base/gdevpdfv.c +++ b/gs/base/gdevpdfv.c @@ -151,11 +151,23 @@ pdf_pattern(gx_device_pdf *pdev, const gx_drawing_color *pdc, cos_dict_t *pcd_XObject = cos_dict_alloc(pdev, "pdf_pattern(XObject)"); char key[MAX_REF_CHARS + 3]; cos_value_t v; + cos_object_t *object; if (pcd_XObject == 0) return_error(gs_error_VMerror); sprintf(key, "/R%ld", pcs_image->id); - COS_OBJECT_VALUE(&v, pcs_image); + /* This is non-obvious code. Previously we would put the image object (pcs_image) + * into the Resources dit. When we come to write out the Resources dict + * that code writes a reference (index 0 R) using the ID from the object. + * However that means we have two pointers to the XObject. One in the chain + * of resoruces (which we need in order to write teh XObject) and one from + * the pattern here. That seriously messes up memory handling. So instead + * we now make a new object, and copy the id from the pcs_image. Since that's + * all that the writing code will use, we cna avoid the double pointers. + */ + object = cos_reference_alloc(pdev, "pdf_pattern(reference copy of XObject)"); + object->id = pcs_image->id; + COS_OBJECT_VALUE(&v, object); if ((code = cos_dict_put(pcd_XObject, (byte *)key, strlen(key), &v)) < 0 || (code = cos_dict_put_c_key_object(pcd_Resources, "/XObject", COS_OBJECT(pcd_XObject))) < 0 diff --git a/gs/base/gdevpdfx.h b/gs/base/gdevpdfx.h index ef1a2e293..bc834cf6d 100644 --- a/gs/base/gdevpdfx.h +++ b/gs/base/gdevpdfx.h @@ -166,6 +166,14 @@ typedef enum { * for synthesized fonts, rname is A, B, .... The string is null-terminated. */ + /* WARNING WILL ROBINSON! + * these 2 pointers may *look* like a double linked list but in fact these are pointers + * to two *different* single-linked lists. 'next' points to the next resource + * of this type, which is stored in the resource chains pointed to by the array + * 'resources' in the device structure. 'prev' is a pointer + * to the list of stored resources of all types, pointed to by the + * 'last_resource' member of the device structure. + */ #define pdf_resource_common(typ)\ typ *next; /* next resource of this type */\ pdf_resource_t *prev; /* previously allocated resource */\ @@ -257,6 +265,10 @@ struct pdf_article_s { /* ---------------- The device structure ---------------- */ /* Resource lists */ +/* We seem to split the resources up into 'NUM_RESOURCE_CHAINS' linked + * lists purely as a performance boost. Presumably it save searching very + * long lists. + */ #define NUM_RESOURCE_CHAINS 16 typedef struct pdf_resource_list_s { pdf_resource_t *chains[NUM_RESOURCE_CHAINS]; diff --git a/gs/base/gdevpdt.c b/gs/base/gdevpdt.c index 6794b5f06..b46efd563 100644 --- a/gs/base/gdevpdt.c +++ b/gs/base/gdevpdt.c @@ -51,3 +51,14 @@ pdf_text_data_alloc(gs_memory_t *mem) ptd->text_state = pts; return ptd; } + +int text_data_free(gs_memory_t *mem, pdf_text_data_t *ptd) +{ + gs_free_object(mem, ptd->outline_fonts->standard_fonts, "Free text Outline standard fonts");; + gs_free_object(mem, ptd->outline_fonts, "Free text Outline fonts");; + gs_free_object(mem, ptd->bitmap_fonts, "Free text Bitmap fotns");; + gs_free_object(mem, ptd->text_state, "Free text state");; + gs_free_object(mem, ptd, "Free text"); + + return 0; +} diff --git a/gs/base/gdevpdt.h b/gs/base/gdevpdt.h index f49271db7..de7cbf89b 100644 --- a/gs/base/gdevpdt.h +++ b/gs/base/gdevpdt.h @@ -42,6 +42,8 @@ pdf_text_state_t *pdf_text_state_alloc(gs_memory_t *mem); */ pdf_text_data_t *pdf_text_data_alloc(gs_memory_t *mem); /* gdevpdts.h */ +int text_data_free(gs_memory_t *mem, pdf_text_data_t *ptd); + /* * Reset the text state at the beginning of the page. */ diff --git a/gs/base/gdevpdtb.c b/gs/base/gdevpdtb.c index dca3dd251..ca9b7b52e 100644 --- a/gs/base/gdevpdtb.c +++ b/gs/base/gdevpdtb.c @@ -320,6 +320,7 @@ pdf_base_font_alloc(gx_device_pdf *pdev, pdf_base_font_t **ppbfont, If the failed glyph will be used in the document, another error will hgappen when the glyph is used. */ + gs_free_copied_font(complete); complete = copied; } } else diff --git a/gs/base/gdevpdtd.c b/gs/base/gdevpdtd.c index 560018d23..e991f4ab2 100644 --- a/gs/base/gdevpdtd.c +++ b/gs/base/gdevpdtd.c @@ -19,6 +19,7 @@ #include "gserrors.h" #include "gsrect.h" /* for rect_merge */ #include "gscencs.h" +#include "gxfcopy.h" #include "gdevpdfx.h" #include "gdevpdfo.h" /* for object->written */ #include "gdevpdtb.h" @@ -255,6 +256,27 @@ pdf_font_descriptor_alloc(gx_device_pdf *pdev, pdf_font_descriptor_t **ppfd, return 0; } +int pdf_font_descriptor_free(gx_device_pdf *pdev, pdf_resource_t *pres) +{ + pdf_font_descriptor_t *pfd = (pdf_font_descriptor_t *)pres; + pdf_base_font_t *pbfont = pfd->base_font; + gs_font *copied = (gs_font *)pbfont->copied; + + gs_free_copied_font(copied); + if (pbfont && pbfont->font_name.size) { + gs_free_string(pdev->memory, pbfont->font_name.data, pbfont->font_name.size, "Free BaseFont FontName string"); + pbfont->font_name.data = (byte *)0L; + pbfont->font_name.size = 0; + } + if (pbfont) + gs_free_object(cos_object_memory(pres->object), pbfont, "Free base font from FontDescriptor)"); + if (pres->object) { + gs_free_object(cos_object_memory(pres->object), pres->object, "free FontDescriptor object"); + pres->object = NULL; + } + return 0; +} + /* Get the object ID of a FontDescriptor. */ long pdf_font_descriptor_id(const pdf_font_descriptor_t *pfd) diff --git a/gs/base/gdevpdtd.h b/gs/base/gdevpdtd.h index cf810b06e..835ca9ae5 100644 --- a/gs/base/gdevpdtd.h +++ b/gs/base/gdevpdtd.h @@ -68,6 +68,8 @@ int pdf_font_descriptor_alloc(gx_device_pdf *pdev, pdf_font_descriptor_t **ppfd, gs_font_base *font, bool embed); +int pdf_font_descriptor_free(gx_device_pdf *pdev, pdf_resource_t *pres); + /* * Get the object ID of a FontDescriptor. */ diff --git a/gs/base/gdevpdtf.c b/gs/base/gdevpdtf.c index 0d2be2bc4..5b1c49d31 100644 --- a/gs/base/gdevpdtf.c +++ b/gs/base/gdevpdtf.c @@ -805,6 +805,8 @@ pdf_compute_BaseFont(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, bool fini default: break; } + if (pdfont->BaseFont.size) + gs_free_string(pdev->pdf_memory, pdfont->BaseFont.data, pdfont->BaseFont.size, "Replacing BaseFont string"); pdfont->BaseFont.data = fname.data = data; pdfont->BaseFont.size = fname.size = size; /* Compute names for subset fonts. */ diff --git a/gs/base/gdevpdti.c b/gs/base/gdevpdti.c index 31cddae7c..f7b4e19da 100644 --- a/gs/base/gdevpdti.c +++ b/gs/base/gdevpdti.c @@ -294,6 +294,25 @@ pdf_attach_charproc(gx_device_pdf * pdev, pdf_font_resource_t *pdfont, pdf_char_ return 0; } +int +pdf_free_charproc_ownership(gx_device_pdf * pdev, pdf_resource_t *pres) +{ + pdf_char_proc_ownership_t *next, *pcpo = (pdf_char_proc_ownership_t *)pres; + + while (pcpo) { + next = pcpo->char_next; + if(pcpo->char_name.size != 0 && pcpo->char_name.data) { + /* This causes PCL some trouble, don't know why yet FIXME-MEMORY + gs_free_string(pdev->pdf_memory, (byte *)pcpo->char_name.data, pcpo->char_name.size, "Free CharProc name");*/ + pcpo->char_name.data = (byte *)0L; + pcpo->char_name.size = 0; + } + gs_free_object(pdev->pdf_memory, pcpo, "Free CharProc"); + pcpo = next; + } + return 0; +} + /* Begin a CharProc for a synthesized (bitmap) font. */ int pdf_begin_char_proc(gx_device_pdf * pdev, int w, int h, int x_width, diff --git a/gs/base/gdevpdti.h b/gs/base/gdevpdti.h index 309089969..5b618d623 100644 --- a/gs/base/gdevpdti.h +++ b/gs/base/gdevpdti.h @@ -66,6 +66,8 @@ int pdf_begin_char_proc(gx_device_pdf * pdev, int w, int h, int x_width, /* End a CharProc. */ int pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos); +int pdf_free_charproc_ownership(gx_device_pdf * pdev, pdf_resource_t *pres); + /* Put out a reference to an image as a character in an embedded font. */ int pdf_do_char_image(gx_device_pdf * pdev, const pdf_char_proc_t * pcp, const gs_matrix * pimat); diff --git a/gs/base/gdevpsdp.c b/gs/base/gdevpsdp.c index b6a619a6c..c2935ce2f 100644 --- a/gs/base/gdevpsdp.c +++ b/gs/base/gdevpsdp.c @@ -298,6 +298,10 @@ psdf_get_image_dict_param(gs_param_list * plist, const gs_param_name pname, code = param_list_copy(dict.list, (gs_param_list *)plvalue); } param_end_write_dict(plist, pname, &dict); + if (dict.list) { + gs_c_param_list_release((gs_c_param_list *)dict.list); + gs_free_object(plist->memory, dict.list, "Free parameter list"); + } return code; } diff --git a/gs/base/gsfcmap.c b/gs/base/gsfcmap.c index fbdfc43a6..d3ea34bee 100644 --- a/gs/base/gsfcmap.c +++ b/gs/base/gsfcmap.c @@ -335,6 +335,13 @@ gs_cmap_alloc(gs_cmap_t **ppcmap, const gs_memory_struct_type_t *pstype, return 0; } +int gs_cmap_free(gs_cmap_t *pcmap, gs_memory_t *mem) +{ + gs_free_object(mem, pcmap->CIDSystemInfo, "gs_cmap_free(CIDSystemInfo)"); + gs_free_object(mem, pcmap, "gs_cmap_free(CMap)"); + return 0; +} + /* * Initialize an enumerator with convenient defaults (index = 0). */ @@ -573,8 +580,10 @@ gs_cmap_ToUnicode_alloc(gs_memory_t *mem, int id, int num_codes, int key_size, g return code; map = (uchar *)gs_alloc_bytes(mem, num_codes * gs_cmap_ToUnicode_code_bytes, "gs_cmap_ToUnicode_alloc"); - if (map == NULL) + if (map == NULL) { + gs_cmap_free(*ppcmap, mem); return_error(gs_error_VMerror); + } memset(map, 0, num_codes * gs_cmap_ToUnicode_code_bytes); cmap = (gs_cmap_ToUnicode_t *)*ppcmap; cmap->glyph_name_data = map; @@ -587,6 +596,13 @@ gs_cmap_ToUnicode_alloc(gs_memory_t *mem, int id, int num_codes, int key_size, g return 0; } +int gs_cmap_ToUnicode_free(gs_memory_t *mem, gs_cmap_t *pcmap) +{ + gs_free_object(mem, pcmap->glyph_name_data, "Free ToUnicode glyph data"); + gs_cmap_free(pcmap, mem); + return 0; +} + /* * Write a code pair to ToUnicode CMap. */ diff --git a/gs/base/gsfcmap.h b/gs/base/gsfcmap.h index aea028c4e..782a690b9 100644 --- a/gs/base/gsfcmap.h +++ b/gs/base/gsfcmap.h @@ -57,6 +57,8 @@ int gs_cmap_decode_next(const gs_cmap_t *pcmap, const gs_const_string *str, int gs_cmap_ToUnicode_alloc(gs_memory_t *mem, int id, int num_codes, int key_size, gs_cmap_t **ppcmap); +int gs_cmap_ToUnicode_free(gs_memory_t *mem, gs_cmap_t *pcmap); + /* * Write a code pair to ToUnicode CMap. */ diff --git a/gs/base/gxfcmap.h b/gs/base/gxfcmap.h index 0bb92cfaa..fe66022be 100644 --- a/gs/base/gxfcmap.h +++ b/gs/base/gxfcmap.h @@ -303,6 +303,8 @@ int gs_cmap_alloc(gs_cmap_t **ppcmap, const gs_memory_struct_type_t *pstype, const gs_cid_system_info_t *pcidsi, int num_fonts, const gs_cmap_procs_t *procs, gs_memory_t *mem); +int gs_cmap_free(gs_cmap_t *pcmap, gs_memory_t *mem); + /* * Initialize an enumerator with convenient defaults (index = 0). */ diff --git a/gs/base/gxfcopy.c b/gs/base/gxfcopy.c index 36797e1f3..825676400 100644 --- a/gs/base/gxfcopy.c +++ b/gs/base/gxfcopy.c @@ -2139,6 +2139,41 @@ gs_copy_font(gs_font *font, const gs_matrix *orig_matrix, gs_memory_t *mem, gs_f return code; } +int gs_free_copied_font(gs_font *font) +{ + gs_copied_font_data_t *cfdata = font->client_data; + gs_memory_t *mem = font->memory; + int i; + gs_copied_glyph_t *pcg = 0; + + /* free copied glyph data */ + for (i=0;i < cfdata->glyphs_size;i++) { + pcg = &cfdata->glyphs[i]; + if(pcg->gdata.size) { + gs_free_string(font->memory, (byte *)pcg->gdata.data, pcg->gdata.size, "Free copied glyph"); + } + } + + if (cfdata) { + uncopy_string(mem, &cfdata->info.FullName, + "gs_free_copied_font(FullName)"); + uncopy_string(mem, &cfdata->info.FamilyName, + "gs_free_copied_font(FamilyName)"); + uncopy_string(mem, &cfdata->info.Notice, + "gs_free_copied_font(Notice)"); + uncopy_string(mem, &cfdata->info.Copyright, + "gs_free_copied_font(Copyright)"); + if (cfdata->Encoding) + gs_free_object(mem, cfdata->Encoding, "gs_free_copied_font(Encoding)"); + gs_free_object(mem, cfdata->glyphs, "gs_free_copied_font(glyphs)"); + gs_free_object(mem, cfdata->names, "gs_free_copied_font(names)"); + gs_free_object(mem, cfdata->data, "gs_free_copied_font(data)"); + gs_free_object(mem, cfdata, "gs_free_copied_font(wrapper data)"); + } + gs_free_object(mem, font, "gs_free_copied_font(copied font)"); + return 0; +} + /* * Copy a glyph, including any sub-glyphs. */ diff --git a/gs/base/gxfcopy.h b/gs/base/gxfcopy.h index c46ca65ec..40a80a875 100644 --- a/gs/base/gxfcopy.h +++ b/gs/base/gxfcopy.h @@ -71,6 +71,8 @@ int gs_copy_font(gs_font *font, const gs_matrix *orig_matrix, gs_memory_t *mem, gs_font **pfont_new, int max_reserved_glyphs); +int gs_free_copied_font(gs_font *font); + /* * Copy a glyph, including any sub-glyphs. The destination font ("copied" * argument) must be a font created by gs_copy_font. The source font @@ -125,6 +127,9 @@ int gs_copy_glyph(gs_font *font, gs_glyph glyph, gs_font *copied); int gs_copy_glyph_options(gs_font *font, gs_glyph glyph, gs_font *copied, int options); +int gs_copied_font_free_glyphs(gs_font *font); +int gs_copied_font_free_data(gs_font *font); + /* * Add an encoding entry to a copied font. If the given encoding entry is * not empty and is not the same as the new value, gs_copied_font_encode diff --git a/gs/psi/iparam.c b/gs/psi/iparam.c index bf19ac437..86e837db7 100644 --- a/gs/psi/iparam.c +++ b/gs/psi/iparam.c @@ -198,6 +198,7 @@ ref_param_end_write_collection(gs_param_list * plist, gs_param_name pkey, &((dict_param_list *) pvalue->list)->dict); gs_free_object(plist->memory, pvalue->list, "ref_param_end_write_collection"); + pvalue->list = 0; return code; } static int |