From c81e15ea58f567dc644103cf135b2bf6e367cb58 Mon Sep 17 00:00:00 2001 From: Marshall Taplits <1051809+mtaplits@users.noreply.github.com> Date: Mon, 14 Sep 2026 14:22:52 -0400 Subject: [PATCH] bannertopdf: close output stream so the generated PDF is not truncated 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 #212 --- cupsfilters/bannertopdf.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cupsfilters/bannertopdf.c b/cupsfilters/bannertopdf.c index 60769e7b2..9b2ce9aa1 100644 --- a/cupsfilters/bannertopdf.c +++ b/cupsfilters/bannertopdf.c @@ -1021,6 +1021,14 @@ cfFilterBannerToPDF(int inputfd, // I - File descriptor input stream unlink(tempfile); if (inputfp) fclose(inputfp); - + // The output stream has to be flushed and closed here. When this filter + // function is called from cfFilterChain() (as the "universal" filter does), + // the parent closes the raw output file descriptor and exits right after + // this function returns, so a still buffered tail of the generated PDF + // (cross-reference table and "%%EOF") would be lost and the following + // filter in the chain would fail to parse the file. + if (outputfp) + fclose(outputfp); + return (ret); }