/src/ghostpdl/pdf/pdf_loop_detect.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2018-2022 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, for further information. |
14 | | */ |
15 | | |
16 | | /* code for handling circular references */ |
17 | | |
18 | | #include "pdf_int.h" |
19 | | #include "pdf_loop_detect.h" |
20 | | |
21 | | static int pdfi_init_loop_detector(pdf_context *ctx) |
22 | 3.88M | { |
23 | 3.88M | if (ctx->loop_detection) { |
24 | 0 | dbgmprintf(ctx->memory, "Attempt to initialise loop detector while one is in operation\n"); |
25 | 0 | return_error(gs_error_unknownerror); |
26 | 0 | } |
27 | | |
28 | 3.88M | ctx->loop_detection = (uint64_t *)gs_alloc_bytes(ctx->memory, INITIAL_LOOP_TRACKER_SIZE * sizeof (uint64_t), "allocate loop tracking array"); |
29 | 3.88M | if (ctx->loop_detection == NULL) |
30 | 0 | return_error(gs_error_VMerror); |
31 | | |
32 | 3.88M | ctx->loop_detection_entries = 0; |
33 | 3.88M | ctx->loop_detection_size = INITIAL_LOOP_TRACKER_SIZE; |
34 | 3.88M | return 0; |
35 | 3.88M | } |
36 | | |
37 | | static int pdfi_free_loop_detector(pdf_context *ctx) |
38 | 3.88M | { |
39 | 3.88M | if (ctx->loop_detection == NULL) { |
40 | 0 | dbgmprintf(ctx->memory, "Attempt to free loop detector without initialising it\n"); |
41 | 0 | return 0; |
42 | 0 | } |
43 | 3.88M | if (ctx->loop_detection != NULL) |
44 | 3.88M | gs_free_object(ctx->memory, ctx->loop_detection, "Free array for loop tracking"); |
45 | 3.88M | ctx->loop_detection_entries = 0; |
46 | 3.88M | ctx->loop_detection_size = 0; |
47 | 3.88M | ctx->loop_detection = NULL; |
48 | | |
49 | 3.88M | return 0; |
50 | 3.88M | } |
51 | | |
52 | | int pdfi_loop_detector_add_object(pdf_context *ctx, uint64_t object) |
53 | 11.9M | { |
54 | 11.9M | if (ctx->loop_detection == NULL) { |
55 | 0 | dbgmprintf(ctx->memory, "Attempt to use loop detector without initialising it\n"); |
56 | 0 | return 0; |
57 | 0 | } |
58 | | |
59 | 11.9M | if (ctx->loop_detection_entries == ctx->loop_detection_size) { |
60 | 0 | uint64_t *New; |
61 | |
|
62 | 0 | New = (uint64_t *)gs_alloc_bytes(ctx->memory, (ctx->loop_detection_size + INITIAL_LOOP_TRACKER_SIZE) * sizeof (uint64_t), "re-allocate loop tracking array"); |
63 | 0 | if (New == NULL) { |
64 | 0 | return_error(gs_error_VMerror); |
65 | 0 | } |
66 | 0 | memcpy(New, ctx->loop_detection, ctx->loop_detection_entries * sizeof(uint64_t)); |
67 | 0 | gs_free_object(ctx->memory, ctx->loop_detection, "Free array for loop tracking"); |
68 | 0 | ctx->loop_detection_size += INITIAL_LOOP_TRACKER_SIZE; |
69 | 0 | ctx->loop_detection = New; |
70 | 0 | } |
71 | 11.9M | ctx->loop_detection[ctx->loop_detection_entries++] = object; |
72 | 11.9M | return 0; |
73 | 11.9M | } |
74 | | |
75 | | bool pdfi_loop_detector_check_object(pdf_context *ctx, uint64_t object) |
76 | 4.15M | { |
77 | 4.15M | int i = 0; |
78 | | |
79 | 4.15M | if (ctx->loop_detection == NULL) { |
80 | 40 | dbgmprintf(ctx->memory, "Attempt to use loop detector without initialising it\n"); |
81 | 40 | return 0; |
82 | 40 | } |
83 | | |
84 | 10.9M | for (i=0;i < ctx->loop_detection_entries;i++) { |
85 | 6.83M | if (ctx->loop_detection[i] == object) { |
86 | 21.5k | char info_string[256]; |
87 | 21.5k | gs_snprintf(info_string, sizeof(info_string), "Error! circular reference to object %"PRIu64" detected.\n", object); |
88 | 21.5k | pdfi_set_error(ctx, 0, NULL, E_PDF_CIRCULARREF, "pdfi_loop_detector_check_object", info_string); |
89 | 21.5k | return true; |
90 | 21.5k | } |
91 | 6.83M | } |
92 | 4.13M | return false; |
93 | 4.15M | } |
94 | | |
95 | | int pdfi_loop_detector_mark(pdf_context *ctx) |
96 | 7.32M | { |
97 | 7.32M | int code = 0; |
98 | | |
99 | 7.32M | if (ctx->loop_detection == NULL) { |
100 | 3.88M | code = pdfi_init_loop_detector(ctx); |
101 | 3.88M | if (code < 0) |
102 | 0 | return code; |
103 | 3.88M | } |
104 | | |
105 | 7.32M | return pdfi_loop_detector_add_object(ctx, 0); |
106 | 7.32M | } |
107 | | |
108 | | int pdfi_loop_detector_cleartomark(pdf_context *ctx) |
109 | 7.32M | { |
110 | 7.32M | if (ctx->loop_detection == NULL) { |
111 | 610 | dbgmprintf(ctx->memory, "Attempt to use loop detector without initialising it\n"); |
112 | 610 | return 0; |
113 | 610 | } |
114 | | |
115 | 11.9M | while (ctx->loop_detection[--ctx->loop_detection_entries] != 0) { |
116 | 4.61M | ctx->loop_detection[ctx->loop_detection_entries] = 0; |
117 | 4.61M | } |
118 | | /* FIXME - potential optimisation |
119 | | * Instead of freeing the loop detection array every tiome we are done with it |
120 | | * and then reallocating a new one next time we need one, we could just keep |
121 | | * the existing (empty) array. I suspect this would provide a small performance |
122 | | * improvement. |
123 | | */ |
124 | 7.32M | if (ctx->loop_detection_entries == 0) |
125 | 3.88M | pdfi_free_loop_detector(ctx); |
126 | 7.32M | return 0; |
127 | 7.32M | } |