summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Sharp <ken.sharp@artifex.com>2022-08-11 19:16:59 +0100
committerKen Sharp <ken.sharp@artifex.com>2022-08-11 19:32:11 +0100
commit30360aca75851e6877765a7b11963cb5c8f5b0d1 (patch)
treedb03cabcd1204c45cd9a372e68ead69c5a47718a
parent9c7e1ec6a88a53873fd44de672f8bade0bf539d1 (diff)
downloadghostpdl-30360aca75851e6877765a7b11963cb5c8f5b0d1.tar.gz
GhostPDF - Don't follow Parent key in Pages dictionary for Resources
When finding a named resource we check the current dictionary (which may be a Pattern, Xobject, Page etc) and if we fail to find the resource we look to see if the dictionary has a Parent entry (for Resource inheritance) and look in that. If the current dictionary is of /Type /Page, don't do that, because the Parent will be the Pages tree and we can end up creating a cyclic reference between the Pages tree and the page dictionary. Showed up as a memory leak (because we failed to free the page dictionary) with a few OSS-fuzz files.
-rw-r--r--pdf/pdf_doc.c49
1 files changed, 31 insertions, 18 deletions
diff --git a/pdf/pdf_doc.c b/pdf/pdf_doc.c
index 8c4f64d3f..fb5d4f491 100644
--- a/pdf/pdf_doc.c
+++ b/pdf/pdf_doc.c
@@ -823,12 +823,15 @@ int pdfi_find_resource(pdf_context *ctx, unsigned char *Type, pdf_name *name,
{
pdf_dict *typedict = NULL;
pdf_dict *Parent = NULL;
+ pdf_name *n = NULL;
int code;
*o = NULL;
/* Check the provided dict, stream_dict can be NULL if we are trying to find a Default* ColorSpace */
if (dict != NULL) {
+ bool deref_parent = true;
+
code = pdfi_resource_knownget_typedict(ctx, Type, dict, &typedict);
if (code < 0)
goto exit;
@@ -839,30 +842,40 @@ int pdfi_find_resource(pdf_context *ctx, unsigned char *Type, pdf_name *name,
}
/* Check the Parents, if any */
- code = pdfi_dict_knownget_type(ctx, dict, "Parent", PDF_DICT, (pdf_obj **)&Parent);
- if (code < 0)
- goto exit;
- if (code > 0) {
- if (ctx->page.CurrentPageDict != NULL && Parent->object_num != ctx->page.CurrentPageDict->object_num) {
- if (pdfi_loop_detector_check_object(ctx, Parent->object_num) == true)
- return_error(gs_error_circular_reference);
+ /* If the current dictionary is a Page dictionary, do NOT dereference it's Parent, as that
+ * will be the Pages tree, and we will end up with circular references, causing a memory leak.
+ */
+ if (pdfi_dict_knownget_type(ctx, dict, "Type", PDF_NAME, (pdf_obj **)&n)) {
+ if (pdfi_name_is(n, "Page"))
+ deref_parent = false;
+ pdfi_countdown(n);
+ }
- code = pdfi_loop_detector_mark(ctx);
- if (code < 0)
- return code;
+ if (deref_parent) {
+ code = pdfi_dict_knownget_type(ctx, dict, "Parent", PDF_DICT, (pdf_obj **)&Parent);
+ if (code < 0)
+ goto exit;
+ if (code > 0) {
+ if (ctx->page.CurrentPageDict != NULL && Parent->object_num != ctx->page.CurrentPageDict->object_num) {
+ if (pdfi_loop_detector_check_object(ctx, Parent->object_num) == true)
+ return_error(gs_error_circular_reference);
+
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
- code = pdfi_loop_detector_add_object(ctx, dict->object_num);
- if (code < 0) {
+ code = pdfi_loop_detector_add_object(ctx, dict->object_num);
+ if (code < 0) {
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ return code;
+ }
+ code = pdfi_find_resource(ctx, Type, name, Parent, page_dict, o);
(void)pdfi_loop_detector_cleartomark(ctx);
- return code;
+ if (code != gs_error_undefined)
+ goto exit;
}
- code = pdfi_find_resource(ctx, Type, name, Parent, page_dict, o);
- (void)pdfi_loop_detector_cleartomark(ctx);
- if (code != gs_error_undefined)
- goto exit;
}
}
-
pdfi_countdown(typedict);
typedict = NULL;
}