bannertopdf: close output stream so the generated PDF is not truncated - #249
Merged
tillkamppeter merged 1 commit intoSep 14, 2026
Merged
Conversation
cfFilterBannerToPDF() never closed the FILE * it fdopen()s on outputfd on the success path, so any still buffered tail of the generated PDF was lost whenever the caller closed the raw output file descriptor and exited right after the filter function returned. cfFilterChain() does exactly that, so with the "universal" filter the following pdftopdf received a truncated PDF (missing the cross-reference table and the %%EOF marker), failed to parse it and exited with status 1. This broke printing the CUPS test page (application/vnd.cups-pdf-banner) and banner pages (job-sheets). It is a regression from 1.x, where bannertopdf was a standalone filter writing to stdout and normal process exit flushed the stream; the 2.x rewrite turned it into an in-process library function called by cfFilterChain(). Verified on master: the universal filter chain exits 1 with 4 bytes of output before the change and 0 with a complete page after it. Fixes OpenPrinting#212
castrojo
added a commit
to projectbluefin/fsdk-containers
that referenced
this pull request
Sep 25, 2026
) libcupsfilters 2.2.1's cfFilterBannerToPDF() never fcloses its fdopen(outputfd) stream. When cfFilterChain() runs it in-process, the parent closes outfd and exits right after the function returns, so the buffered tail of the banner/test-page PDF is lost. pdftopdf then gets empty or truncated input and the job aborts with 0 bytes. Backport the upstream fix (OpenPrinting/libcupsfilters#249, commit 1e66af6, on master after 2.2.1) into patches/printing/libcupsfilters/. The existing libcupsfilters patch_queue picks it up through the junction's local source staging. Only libcupsfilters and its printing reverse deps change keys (cups-filters, libppd, pappl-retrofit, base); every other element keeps its key on both arches. Signed-off-by: castrojo <castrojo@users.noreply.github.com> Co-authored-by: castrojo <castrojo@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #212.
Problem
cfFilterBannerToPDF()opens a stream on the output file descriptor withfdopen(outputfd, "w"), but on the success path it never closes it —fclose(outputfp)only appears on the error paths. The stream therefore keeps its last buffer, andcfFilterChain()closes the raw output fd and exits immediately after the filter function returns, so that tail is discarded.The lost bytes are the cross-reference table and the
%%EOFmarker. With theuniversalfilter the next filter in the chain,pdftopdf(backed by PDFio), cannot parse the file and exits with status 1, which kills the chain:This breaks printing the CUPS test page (
application/vnd.cups-pdf-banner) and banner pages (job-sheets=standard). Ordinary documents are unaffected because their chains do not start with bannertopdf.It is a regression from 1.x: there
bannertopdfwas a standalone filter binary writing to stdout, so normal process exit flushed the stream. The 2.x rewrite made it an in-process library function invoked bycfFilterChain()/cfFilterUniversal(), where the caller closes the fd and exits without giving the filter a chance to flush.Verification on master
Running the
universalfilter on the test page template, before and after this change (builds of this branch, same configuration):pdftopdfstopped with status 1bannertopdfrun standalone produces 49736 bytes for the same input; in the chainpdftopdfwas receiving 49152 = 12 × 4096, i.e. truncated exactly on a stdio buffer boundary, with the missing 584 bytes being the xref table and%%EOF.Content after the fix is intact: the page renders with the same ink density as the template scaled to the same canvas (0.64% vs 2.55% for
default-testpage.pdf, ratio 0.252 against a 4×6-to-A4 area ratio of 0.248).Notes
make check: 7 pass, 4 fail —testpdf2,test-analyze,test-pdf,test-ps, all withFont no was not loaded, i.e. the missingttf-dejavucheckdep. These fail identically without this change and are unrelated to it.cfFilterBannerToPDF()at all, which is why this regression was not caught. I have not added a test here since it would need a new fixture (a PDF-io-based assertion on the generated stream); happy to add one if you would like it in this PR.cfPDFPagesFP()(cupsfilters/pdf.c, missingfflush()beforepdfioFileOpen()) is already fixed upstream bye14bad4061/ Fix printing error: pdfio output "Missing Root object." #167 and is not touched here.