summaryrefslogtreecommitdiff
path: root/psi
Commit message (Collapse)AuthorAgeFilesLines
* Squash various warnings.Robin Watts2023-05-152-1/+1
| | | | | | | Unused variables, 'may be used unset' or implementations not matching prototypes. These show up now as the gcc version on the nodes has increased.
* Ghostscript - split up PDF operator tableKen Sharp2023-05-052-4/+10
| | | | | | | | | | Bug #706705 "zpdfops_op_defs[] table overflow" If HAVE_LIBIDN is true then we would have more than 16 operators in the table, which is the maximum (obviously this is not true on the cluster) Split the table up by moving the old PDF interpreter operators into a new table to make it easier to get rid of them in future.
* Fix missing ctypes_.h inclusionChris Liddell2023-05-021-0/+1
| | | | for tolower() prototype.
* Fix pdfi related dict ref object garbage collectionChris Liddell2023-04-282-1/+3
| | | | | | | | | | | Unlike any other object type, ref objects do not have their mark bit unset during the first phase of a garbage collection. They, in fact, require the bit to be unset explicitly at the end of the reloc phase. This was an omission from: https://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff;h=b0739b945394ec81a
* MSVC: Add support for another version of nmake.Robin Watts2023-04-261-0/+5
|
* Avoid in use names being garbage collectedChris Liddell2023-04-211-1/+22
| | | | | | | | | | | | | | | | | | | To maintain interoperability with the Postscript interpreter, pdfi shares the Postscript name table (when it's built into gs, rather than standalone). On the basis that the name table is cleaned up only with global VM, and that global VM is only gc'ed at the end of job (we thought!), we thought adding names to the table was sufficient. Turns out, there are circumstances under which global VM (and thus the name table) do get gc'ed before the end of job, and in that case, names pdfi still relied upon could disappear. To avoid that, add the names (as key and value) to a Postscript dictionary, known to the garbager, at the same time as we add them to the name table. Came up cluster testing a fix for Bug 706595, with file: tests_private/comparefiles/Bug691740.pdf
* GhostPDF - fix Portfolio PDF with pdfwriteKen Sharp2023-04-201-261/+304
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | No file or bug report for this, the customer requested the files be kept private. However any PDF Collection (Portfolio) file will show the problem. GhostPDF supports preserving embedded files from the input, but when we are processing a PDF Collection we don't want to do that, because in this case we run each of the embedded files individually. If we copy the EmbeddedFIles as well then we end up duplicating them in the output. So, when processing EmbeddedFiles, check the Catalog to see if there is a /Collection key, if there is then stop processing EmbeddedFiles. The customer also pointed out there was no way to avoid embedding any EmbeddedFiles from the input, so additionally add a new switch -dPreserveEmbeddedFiles to control this. While we're doing that, add one to control the preservation of 'DOCVIEW' (PageMode, PageLayout, OpenAction) as well, -dPreserveDocView. This then leads on to preventing the EmbeddedFiles in a PDF Collection from writing their DocView information. If we let them do that then we end up opening the file incorrectly. To facilitate similar changes in the future I've rejigged the way .PDFInit works, so that it calls a helper function to read any interpreter parameters and applies them to the PDF context. I've also added a new PostScript operator '.PDFSetParams' which takes a PDF context and a dictionary of key/value pairs which it applies to the context. Sadly I can't actually use that for the docview control, because the PDF initialisation is what processes the document, so changing it afterwards is no help. So I've altered runpdfbegin to call a new function runpdfbegin_with_params and pass an empty dictionary. That then allows me to call runpdfbegin_with_params from the PDF Collection processing, and turn off PreserveDocView. So in summary; new controls PreserveDocView and PreserveEmbeddedFiles and a new function .PDFSetParams to allow us to alter the PDF interpreter parameters after .PDFInit is executed. PDF Collections no longer embed duplicate files.
* PostScript interpreter - don't rotate content onto square mediaKen Sharp2023-04-101-6/+12
| | | | | | | | | | Bug #706563 "PagSize Policy 3 can inappropriately rotate content" As noted, if the medium is square, and the requested medium is portrait, then we would end up rotating the content. To avoid this, just check if the medium or request is square, and if so set rotate to 0.
* Ghostscript - convert the system default paper size to lower caseKen Sharp2023-04-051-1/+5
| | | | | | | | | | | | | | | | | | Bug 706544 "Unknown .defaultpapersize: (Letter). error shown at startup" The problem appears to be that the system libpaper is configured to have a default paper size of 'Letter' rather than the all lower case 'letter', so Ghostscript doesn't have a matching media size. libpaper says that lower case is 'preferred' but there's apparently no reason why we couldn't also have (for example) A4 instead of a4. We can tackle this by making the system defined paper size lower case before returning it to Ghostscript. However, a few of the paper sizes in statusdict do have upper case characters in their name, so we need to duplicate those few sizes as lower case. The contents of statusdict, and in particular the defined media sizes, are not specified so we're OK to do this.
* Update postal address in file headersChris Liddell2023-04-04282-843/+847
|
* Bug 706478: pdfwrite: Substituted TTF CIDFont CID handlingChris Liddell2023-03-151-27/+46
| | | | | | | | | | The PS interpreter callback that handles converting a CID to a TTF GID did not handle the case of substituted CIDFonts. It requires looking up the CID on the Decoding (to get a Unicode code point), and then looking up the code point in the TTF cmap table to get the GID. The rendering code already handled it.
* GhostPDF - Fix annotation visibility detection, improve -dPrinted.Ken Sharp2023-03-141-0/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Bug #706441 "AcroForm field Btn with no AP not implemented" The title is misleading. The actual problem is that when checking to determine the 'visibility' of an annotation, the NoView bit was being checked with the wrong bit set in the mask. This led to the annotation not being visible and not rendering. From there; the old PDF interpreter used the presence of an OutputFile on the command line to determine whether or not the output should be treated as 'printer' or 'viewer'. The display device doesn't take an OutputFIle so we treat that as a viewer. We weren't taking that action at all internally. So pass OutputFile in from the PostScript world if it is present, and look for it on the command line if we are stand-alone. Start by assuming we are a printer. If we find an OutputFile, and have not encountered a 'Printed' switch, then assume we are a printer. Secondly; deal with the warnings. These are real but are the wrong place for a warning. The problem is that we have an annotation which has an /AP dictionary: << /D <</Off 723 0 R/renew 724 0 R>> /N <</renew 722 0 R>> >> We pick up the Normal (/N) key/value and see that the value is a dictionary. So we consult the annotation for a /AS (appearance state) which in this case is defined as: /AS/Off So we then try to find the /Off state in the sub-dictionary. There isn't one. The specification has nothing to say about what we should do here. I've chosen to replace the appearance with a null object and alter the drawing routine to simply silently ignore this case. Final note; the code is now behaving as it is expected to, but the file in bug #706441 will still be missing a number of buttons when rendered, because these buttons are only drawn when the application is a viewer. In order to have them render Ghostscript must be invoked with : -dPrinted=false
* Update -Z! output to include error returns.Robin Watts2023-03-101-1/+3
| | | | | This makes it easier to see which exact interpreter function is throwing an error.
* Bug 706466: Avoid NULL deref in file access code.Robin Watts2023-03-091-0/+4
| | | | | | Check a function pointer is non-NULL before calling it. Thanks to Youngseok Choi for the report.
* Bug 706465: Avoid zero-page access in swift interpreter exit.Robin Watts2023-03-091-12/+15
| | | | | | | | If "-Z:" debugging is enabled, and the interpreter exits without doing anything, we can attempt to access a memory structure without it being there. Guard against this. Thanks to Youngseok Choi for the report!
* Bug 706389: Fix versioning format consistencyChris Liddell2023-02-272-5/+9
| | | | | | | | | | | | | The main code issue with this bug was that the banner printed on startup is printed from Postscript, and Postscript's cvs operator doesn't allow for dictating the number of digits it outputs so the number 00 will always end up as the string "0", or 01 as "1". So our 10.01.0 version would be printed as "10.1.0". To address this, as a ".revisionstring" entry to systemdict, created during startup, the string is created in C, so we control the format. The remaining issues need to be address as part of the release process.
* Use appropriate attributes for ref pointing to text enumeratorChris Liddell2023-02-141-2/+3
| | | | | | | | | | | | | | | | | | | | In order to facilitate exiting to the interpreter during text operations (such as show, stringwidth etc) we store the text enumerator in an opaque Postscript object on the execution stack. Postscript refs have an attribute indicating what VM mode the object they reference lives in (local, global or "system"). One of the places that uses that is the garbage collector - if we're gc-ing local VM, we ignore refs with the global attribute. The problem is, we *always* allocate the text enumerator in local VM, but we set the ref attributes with the current VM mode, meaning the enumerator would never get marked by the garbager, and could be freed prematurely by the sweep. Explicitly set the attributes to reflect the actual VM mode used to create the enumerator. Stems from work related to Bug 706368
* Fix having to "quit" twice from the PS executiveChris Liddell2023-02-141-1/+3
| | | | By correcting mistake in e8da62c6ab890c6a2776
* Ghostscript - clean up exec stack on error sampling functionsKen Sharp2023-02-141-1/+2
| | | | | | | | | | | | | | | OSS-fuzz #55898 When sampling a PostScript function, if the supplied function consumes more operands from the operand stack than were present, then we throw an error, attempt to unwind the stack and exit. However, we weren't cleaning up the execution stack. This could eventually lead to us trying to execute the completion routine stored there, which would fail badly. This commit just tidies up the execution stack, removing the objects we no longer need when returning an error.
* oss-fuzz 55443: Dangling reference in extreme out-of-memory conditionChris Liddell2023-02-101-1/+11
| | | | | | | | | | | If we've exhausted memory to the extent that we cannot even run the Postscript error handler properly, we can end up with references to the arrays that contain the record of the stacks' content in $error lasting until the final garbage collection, with the arrays themselves having been freed by the end-of-job restore. So explicitly remove those references and clear the operand stack before we tackle the final stages of shutting down.
* Fix compiler warnings in psi/Chris Liddell2023-01-042-6/+3
| | | | Unused variables
* Coverity ID 382008 - NULL pointer derefernceKen Sharp2022-11-221-1/+7
| | | | | | | | | The pointer dereference is in a memcpy, but I believe that when this happens (pda->base is NULL) then the input data will have been exhausted and so 'len' the bytes to copy will always be zero. While I don't know of any C run-time which will cause an actual problem with this, it seems sensible to avoid it.
* Move gp_wutf8 functions to be gp_utf8.Robin Watts2022-11-213-14/+14
| | | | | | Promote previously windows specific functions to be generically available (and give them names that reflect that).
* MSVC build: Add new version of nmake.Robin Watts2022-11-211-0/+5
|
* Allow @file syntax to include files in the ROM file systemKen Sharp2022-11-216-33/+21
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This started as a customer request, where the customer wanted to store a file in the ROM file system with a bunch of command line parameters in it, and then use the @file syntax to run that file and setup the interpreter. In essence a 'canned' setup stored in the ROM file system. That didn't work, at all, because of a dichotomy in the logic of argument processing. The code used 'lib_file_open' in order to find the file using the search path which, on Ghostscript, includes all the iodevices, Rom file system, RAM file system etc. That function returns a stream which the calling function 'lib_fopen' would then reach inside and pull out the pointer to the underlying gp__file *, and return, because the argument processing was written to use a gp_file *, not a stream *. But.... For the ROM file system, what we store in the 'file' member of the stream is not a gp_file *, its a 'node' *. Trying to use that as a gp_file * rapidly leads to a seg fault. So this commit reworks the argument processing to use a stream * instead of a gp_file *. In reality there is no real difference to the logic we simply use a different call. There are a lot of fiddly references to change unfortunately. There are some consequences; we need to pass stream * around instead of gp_file *, and in particular the 'encoding' functions, which are OS-specific need to use a stream *. This isn't a problem for the interpreters and graphics library, but mkromfs *also* uses those OS-specific files, and it does not have the stream library available. Rather than trying to include it, we note that we don't actually need to use these functions for mkromfs and we do the same hackery as for other missing functionality; we define a stub function that does nothing but will permit the compile to complete.
* PostScript interpreter - Use the correct ref for DeviceN /All inkKen Sharp2022-11-171-4/+3
| | | | | | | | | | | | | | | | | | | | | File from customer, no bug report. We have special processing for the /All ink in a DeviceN colour space, and that processing was assuming that the ink name was a name object which it then wanted to turn into a string object in order to get the actual string representing the name. The file in question, however, defines the names array (quite legally) as: [(All)] So the ink name is a string, not a name. The code explicitly used name_string_ref to turn the name into a string, which unsurprisingly failed because the object isn't a name. In fact we have already dealt with this earlier in the code, all we need to do is use the correct variable and it all works correctly.
* Windows Installer: Override /S setting..Chris Liddell2022-11-091-0/+1
| | | | .. effectively disabling silent installs
* Bug 706058: Run cidfmap generation without showing a cmd windowChris Liddell2022-11-081-1/+4
| | | | | | | | In the Windows installer, it optionally runs gs with a Postscript program to generate a basic cidfmap. Previously, in doing so, the command prompt window would momentarily appear as the executable ran. This changes it so that command prompt window no longer appears.
* GhostPDF + GS - fix ShowAnnotTypes and PreserveAnnotTypesKen Sharp2022-10-281-11/+35
| | | | | | | | | | | | | | | | | Bug #706036 "-dPreserveAnnots=false disregards /ShowAnnotTypes []" There were a couple of problems here. Firstly the switches were mis-spelled as SHOWANNOTTYPES and PRESERVEANNOTTYPES in both pdf_main.ps (passing the values to the PDF interpreter) and in the PDF interpreter itself. This meant that neither switch was being processed. In addition the code to read the values was incorrectly assuming that the value was a 'list' of strings. This is not the case for either control, and indeed simply isn't possible in PostScript. In both cases the value should be an array of names. The code now accepts an array of either names or strings for both keys from PostScript.
* oss-fuzz 52636: Check ref type before usingChris Liddell2022-10-241-0/+4
| | | | | | | | | For Type42/TTF fonts we store the sfnts data in an array of strings, which the FAPI code "seeks" through to read the font data. In this case, one of the elements in the array is an integer rather than string, and since we weren't checking the ref type, using is as a string would crash. Add a check for the ref type, and throw an error if it's not a string.
* Fix gpdl Windows build when SO lib isn't being linkedChris Liddell2022-10-111-0/+6
|
* Update GPDL SO target.Robin Watts2022-09-271-1/+8
| | | | Link with an external SO lib, rather than calling out to an exe.
* GhostPDF - PDFSTOPONWARNING should include PDFSTOPONERRORKen Sharp2022-09-231-0/+2
| | | | | According to the documentation, if we set PDFSTOPONWARNING it sets PDFSTOPONERROR, and we weren't doing that.
* Update Windows installer to play nicer with new docsChris Liddell2022-09-211-4/+4
|
* Add gpdl support for SmartOffice integration.Robin Watts2022-09-191-0/+22
| | | | | No actual SmartOffice code here, just the framework for adding the (private) "SO" interpreter.
* GhostPDF + GS - improve error handlingKen Sharp2022-08-261-0/+19
| | | | | | | | | | | | | | | | Arising from Bug #705784, if we hadn't built the PDF interpreter we would get typecheck errors which were somewhat misleading as to the source of the problem. This commit tidies up the error handling in the area of .PDFInit so that we not only detect the problem there but give a warning that it occurred. In addition, add a means to detect if the PDF interpreter is built in before we stat trying to process a PDF file and, if it is not, give a sensible error message. Tested with BUILD_PDF 0 and with NEWPDF true and false.
* graphics library - prevent seg fault in .tempfileKen Sharp2022-08-261-4/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | Coverity ID #380524 A seg fault can be reproduced on Windows using this PostScript: (d:\\temp) (w+) .tempfile The problem occurs because on Windows gp_file_name_is_absolute permits either '\' or '/' to be used as a separator, but gp_file_name_separator can (obviously) only return one separator, in this case '/'. This means the loop stripping the prefix fails to find any separator and exits with plen = -1, which causes a seg fault in the memcpy below. The first part of the fix is to check plen and if it's less than 0 exit with an error. The remainder of the commit changes from using the separator string to calling gp_file_name_check_separator instead. This has two benefits; firstly it means that on Windows both separators can be detected, secondly for OS's where the separator is more than a single byte we can still detect it, which we could not before. Ghostscript itself never uses .tempfile with a filename, so this can only occur with PostScript input.
* GhostPDF - use recursive array fetch to avoid circular referenceKen Sharp2022-08-231-1/+1
| | | | Bug #705777 " stack overflow in psi/idict.c:160 dict_alloc (exploitable)"
* Bug 705732: Add param and type checking for the .PDFparsePageList operatorChris Liddell2022-08-091-1/+9
|
* Coverity ID 379504 - check return codeKen Sharp2022-08-031-17/+38
| | | | | | | | | We weren't checking the return code from pdfi_loop_detector_add_object but on inspection there was redundant code (mark/cleartomark) which this commit also removes. I've also disabled the debugging print code behind its own #if because it was making the debugging noisy.
* GhostPDF - yet more circular references in Info dictionariesKen Sharp2022-08-021-0/+61
| | | | | | | | | | | | | | | | | OSS-fuzz #49703 OSS-fuzz finds another way to evade the circular reference checking on the Info dictionary, this time by having Annots point to the Pages tree instead of the Page, **and** having the Info dictionary point to the first Page dictionary. I was going to dump anything except names and strings from the dictionary, forgetting that we use the same mechanism for returning the Page dictionary, and we need to have that able to deal with arrays at least, for the various Boxes. So add yet more checking to the contents of the PDF object we are being asked to turn into a PostScript object.
* Windows build - Fix versioning of the binariesKen Sharp2022-08-013-8/+8
| | | | | | | | | | | | | | | | | It seems that the same information is stored in two ways in the version resource of Windows binaries. As numeric data and as a human-readable string. With the addition of the patch level we had updated the string data but had omitted to update the numeric information. In addition it appears that we always had the word order reversed, so that instead of (eg) 9.57.1.0 our numeric version was coming out as 0.0.9.57 (wrong order and no patch level, if the patch level had been present this would have read 1.0.9.57). This commit corrects the word order of FILEVERSION and PRODUCTVERSION and adds the patch level to them, which means we also need to define the patch level on the invocation of the Resource Compiler.
* New PageList processing, supporting PDF and XPS random order.Ray Johnston2022-07-301-0/+37
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Supports out-of-order ranges (if the parser allows it and disables the PageHandler, i.e., flp device). Also adds support for ranges appended to the "even" and "odd" keyword following a ":". As before a trailing "-" in a range implies the last page, and as was supported by the previous 'gxps' code, a leading "-" also is the last page. For example, with XPS or PDF: -sPageList=odd:3-7,even:4-8,1-,-1,9 prints pages: 3, 5, 7, 4, 6, 8, 1, 2, ..., last, last, last-1, ..., 1, 9 The PageList string is parsed using C code into an array that consists of an initial int that is > 0 if the list is ordered, followed by sets of 3 integers per range, even/odd flag (odd=1, even=2), start, end. The final 3 ints are 0,0,0 as a marker. The initial int is used by 'pagelist_test_printed' as an index to the next range to be processed when the PageList is used for languages that can only be processed sequentially (e.g. PS and PCL) and is updated when the page passes the end of the current range. A value of -1 means the ranges are not ordered (not strctly increasing). The flp_fillpage is changed to ignore errors from processing the PageList performed by ParsePageList (called from SkipPage) when PageCount is 0 so that parsers that support out of order processing (PDF and XPS) can continue until later. This should have little or no performance impact since it is limited to PageCount == 0. Note that the new PDF parser also uses the C code parser and then uses the array of ranges returned by ".PDFparsePageList". The old PostScript based parser has not been updated, although it is easy to do so.
* OSS-fuzz #49290Ken Sharp2022-07-211-1/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The problem here is an (I think) corrupted TrueType font. One of the glyphs claims to be a component glyph, and the component GID is larger than the number of glyphs in the font (and so is invalid). When we copy the font (which we only do with pdfwrite and ps2write) we try to copy this glyph which is not otherwise used in the document. As part of trying to copy the glyph we try to get the glyph name for both the glyph and the components of the glyph. Normally we walk the font twice, putting the glyph names for each glyph into the name table on the first pass, and then retrieving them on the second. Because the component glyph is not valid, we (obviously) don't find it on the first pass, and don't add it to the name table. On the second pass we use the glyph ID to try and get the name, but because we didn't store it on the first pass there is no such name with that ID, so we get an empty slot back. Which we don't check! We then try to use it which involves dereferencing a NULL pointer, and we crash. This commit checks the GID of the component glyphs and makes sure they are in the valid range so that (hopefully) this can't happen. This also checks the name returned from name_index_ref to ensure it is not an unused name slot, to avoid a crash if we find another route that fails to return a name. We use this a lot in many places and it's not obvious which ones are guaranteed safe and which might not be so I haven't tried to change the other cases.
* Yet another version change for nmake and VS 2019Ken Sharp2022-07-141-0/+5
|
* Ensure pdfi stream lives long enough (use stable_memory)Chris Liddell2022-07-121-2/+2
| | | | | | | | | | | | | | | | | | | To avoid problems with objects moving in gc memory, we "clone" the PS file object in order to pass it into pdfi (it also avoids problems with the PS code moving the file position under pdfi's feet). In the event of an error from pdfi provoking a Postscript error, we can end up with the underlying file object being closed by a PS restore, while the PDF stream still exists. If that then gets restored away, or gc'ed before the pdfctx_t, it will also try to close the underlying file object, causing problems. Moving the PDF stream to stable memory ensuring it won't get restored away, and won't get gc'ed until after the pdfctx_t is freed (by whatever means). That, in turn, means that the pdfctx_t finalize method can take its special action with the cloned stream, specifically intended to avoid exactly this kind of issue.
* Change how pdfi interacts with FAPI for Truetype fontsChris Liddell2022-07-041-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | In PDF, only symbolic Truetype fonts draw marks from the glyph at GID zero (the TTF notdef). But the default TTF notdef is an empty rectangle, rather than the Postscript style non-marking glyph. The FAPI/Freetype incremental interface integration includes code to spot that case, and return an empty glyph. Since PDFs don't do incremental font definitions, the pdfi code simply passed the TTF into FAPI, and onto Freetype as a complete font, so all the glyph lookups were handled inside Freetype, not using the incremental interface. Thus we lost the ability to do that "filtering". Equally, we don't want to take the time to break down the font and "reassemble" it as the Postscript interpreter is forced to do. This implements a hybrid approach where we still pass the font data unchanged into Freetype, but we still use the incremental interface, allowing that notdef filtering to happen. This commit affects a heuristic in freetype which autmatically enables autohinting, meaning we'll no longer get autohinting in cases where we previously did. That gives a perceived drop in quality at low resolutions. Since autohinting can be enabled at the command line, it's not a serious concern.
* SUBSTFONT functionalityChris Liddell2022-07-041-8/+38
| | | | | | | | | | | This was missing from pdfi, so is added here. Also, change the functionality so setting the SUBSTFONT key to "/None" will result in any attempt to fall back to the default font to throw an invalidfont error. Lastly, fix some typos on the parameters being passed from Postscript into pdfi.
* oss-fuzz 48305: Use ref counting for subclass child deviceChris Liddell2022-06-301-3/+4
| | | | | | | | | | | | The .currentoutputdevice (custom) operator leaves the chance that PS VM still has a reference to the "child" of a subclassed device. In normal operation, this isn't a problem, but on an error, that PS reference may persist until after the unsubclass operation, meaning the "child" is freed while there is still an active reference to it. Change the code to use reference counting to ensure that works. This means considerable fiddling to ensure that, after subclassing, anything sent to the (now moribund) child device doesn't end up affecting the parent.
* GhostPDF - circular references in Info dict with PageLabelsKen Sharp2022-06-071-18/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | OSS-fuzz #47571 This one is quite complicated and may need further work in the code for page labels. The problem arises because we deal with page labels before we deal with the Info dictionary passed back to PostScript. The PageLabel handling discovers a circular reference but, unlike every other case, when this happens we do not abort the operation. We simply leave the indirect reference in place and carry on. This is a problem because it means we replace some indirect references with the dereferenced object, but not all of them. When we later run the same operation when parsing the Info dictionary the fact that one object has been dereferenced and stored as a direct object means that we fail to spot the circular reference, because we have not noted the object number of the 'parent' object. Ordinarily this can't happen because the original error would prevent us storing the dereferenced object at any point in the chain. It is likely that we ought to return an error in the case of page labels with a circular reference at least and not simply carry on. I suspect we should always respect the error. Anyway, to work around this, the commit here checks the Info dictionary for circular references before we store it in the PDF context. Any entry which has an error is deleted from the dictionary before we store it. This prevents the circular reference ever appearing. Brute force, but we only do it once and it makes sure we can never end up in this situation.