Skip to content

cfFilterGhostscript: duplex DM3 (Rotated) emits -dcupsInteger1=4294967295; Ghostscript appleraster rangecheck #222

Description

@ashwinsawant

Summary

cfFilterGhostscript() formats PWG/Apple Raster duplex transform fields with %u. For printers that advertise URF duplex mode DM3 (Rotated), raster_base_header() stores CrossFeedTransform/FeedTransform as -1 in the unsigned cupsInteger[1] / cupsInteger[2] slots. That becomes 4294967295 on the Ghostscript command line. Ghostscript's appleraster device reads those parameters with param_read_int() (signed 32-bit), so the job dies with:

ERROR: Error setting cupsInteger1 ...
Unrecoverable error: rangecheck in .putdeviceprops

CUPS then pauses the queue (Job processing failed.). Simplex jobs work. Duplex PDF → URF jobs fail every time.

This is not a cups-browsed or CUPS daemon bug. Driverless IPP just happens to take this path because the printer does not accept PDF.

Environment

  • Arch Linux (Omarchy 4.0.1), aarch64
  • libcupsfilters 2.2.1-2
  • cups-filters 2.0.1-2
  • cups-browsed 2.1.1-1
  • CUPS 2.4.19
  • Ghostscript 10.07.1
  • Printer: EPSON ET-16650 Series (driverless IPP / Apple Raster)
  • urf-supported includes DM3 (Rotated duplex)

Printer document formats: image/pwg-raster, image/urf, image/jpeg, application/vnd.epson.escpr (no PDF).

How to reproduce

  1. Use a driverless IPP queue whose printer advertises URF duplex mode DM3.
  2. Print a PDF with duplex long-edge (Duplex=DuplexNoTumble / sides=two-sided-long-edge).
  3. Filter chain: pdftopdfcfFilterGhostscript (-sDEVICE=appleraster) → IPP backend.

CUPS log from a real job:

FINAL_CONTENT_TYPE=image/urf
argv[5]: ... Duplex=DuplexNoTumble ... InputSlot=Main ... PageSize=Letter ...

cfFilterGhostscript: Ghostscript command line: gs ... -sDEVICE=appleraster ... -dDuplex ...
  -dcupsInteger1=4294967295 -dcupsInteger2=4294967295 -dcupsInteger8=4
  -scupsPageSizeName=Letter -scupsBackSideOrientation=Rotated ...

cfFilterGhostscript: Error setting cupsInteger1 ...
cfFilterGhostscript: Unrecoverable error: rangecheck in .putdeviceprops
Job processing failed.

cupsfilter with only a PPD does not reproduce this: that path never loads printer IPP attributes, so it never applies the DM3 transforms.

It does reproduce with libcupsfilters against the live printer:

data.printer_attrs = cfGetPrinterAttributes("ipp://printer/ipp/print", NULL, 0, NULL, 0, 0);
data.num_options = cupsAddOption("Duplex", "DuplexNoTumble", ...);
cfRasterPrepareHeader(&h, &data, CF_FILTER_OUT_FORMAT_APPLE_RASTER, ...);
/* h.cupsInteger[1] == 4294967295u, (int)h.cupsInteger[1] == -1 */
cfFilterGhostscript(...); /* fails with the Ghostscript line above */

On this Epson that printed:

urf-supported: ... DM3 ...
Duplex=1 Tumble=0
cupsInteger[1] unsigned=4294967295 signed=-1
cupsInteger[2] unsigned=4294967295 signed=-1
cfFilterGhostscript status=1

Isolated Ghostscript confirmation (no printer required)

# Fails (what libcupsfilters currently emits)
gs -dQUIET -dSAFER -dNOPAUSE -dBATCH -sDEVICE=appleraster \
  -sOutputFile=/dev/null -r600x600 \
  -dDEVICEWIDTHPOINTS=612 -dDEVICEHEIGHTPOINTS=792 \
  -dcupsInteger1=4294967295 -dcupsInteger2=4294967295 \
  -c quit
# ERROR: Error setting cupsInteger1 ...
# Unrecoverable error: rangecheck in .putdeviceprops

# Succeeds (the intended PWG transform values)
gs -dQUIET -dSAFER -dNOPAUSE -dBATCH -sDEVICE=appleraster \
  -sOutputFile=/dev/null -r600x600 \
  -dDEVICEWIDTHPOINTS=612 -dDEVICEHEIGHTPOINTS=792 \
  -dcupsInteger1=-1 -dcupsInteger2=-1 \
  -c quit
# INFO: Rendering completed

The full cfFilterGhostscript command line behaves the same way: 4294967295 → exit 255 and empty output; -1 → 76 KB Apple Raster from a 2-page PDF.

Root cause

In cupsfilters/raster.c (raster_base_header()), PWG/Apple Raster duplex with Rotated / DM3 and long-edge (Tumble == CUPS_FALSE) does:

h->cupsInteger[1] = -1;  /* CrossFeedTransform */
h->cupsInteger[2] = -1;  /* FeedTransform */

cupsInteger[] is unsigned, so those become UINT32_MAX. That is the usual two's-complement encoding of -1 in a PWG Raster header and is correct inside the raster header.

In cupsfilters/ghostscript.c (header_to_gs_args()):

for (i = 0; i <= 15; i ++)
  if (h->cupsInteger[i])
  {
    snprintf(tmpstr, sizeof(tmpstr), "-dcupsInteger%d=%u",
             i, (unsigned)(h->cupsInteger[i]));
    cupsArrayAdd(gs_args, strdup(tmpstr));
  }

UINT32_MAX is non-zero, so it is passed as -dcupsInteger1=4294967295. Ghostscript cups/gdevcups.c uses param_read_int() for cupsIntegerN, which cannot hold that value.

cupsInteger8=4 in the failing command is print-quality (normal) and is fine.

Suggested fix

Format the Ghostscript integers as signed, which turns the stored UINT32_MAX back into -1:

snprintf(tmpstr, sizeof(tmpstr), "-dcupsInteger%d=%d",
         i, (int)h->cupsInteger[i]);

That matches how these fields are used as PWG CrossFeed/Feed transforms (±1). Passing -dcupsInteger1=-1 was verified to make Ghostscript 10.07.1 accept the device setup and rasterize the PDF.

Expected

Duplex driverless PDF → Apple/PWG Raster jobs complete. CUPS should not pause the printer.

Actual

Ghostscript aborts during device setup. The job fails and CUPS stops the queue until it is re-enabled.


Disclosure: Debugged, documented, and drafted by Grok (xAI). The failure was reproduced on this machine against libcupsfilters 2.2.1 and Ghostscript 10.07.1; the suggested %d / (int) change was checked with the same Ghostscript command line ( 4294967295 fails, -1 rasterizes). A human is submitting the report.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions