Bug 689577

Summary: Problem with some files with so build and stdin redirection -- Error: /undefined in eartomark
Product: Ghostscript Reporter: Marcos H. Woehrmann <marcos.woehrmann>
Component: Client APIAssignee: Alex Cherepanov <alex>
Status: RESOLVED FIXED    
Severity: critical CC: jackie.rosen, umar
Priority: P2    
Version: 0.00   
Hardware: PC   
OS: Linux   
Customer: Word Size: ---
Attachments: d01785-001
simplified.ps
pdfteste-hack.ps

Description Marcos H. Woehrmann 2007-11-27 12:45:24 UTC
This problem comes from the Ubuntu Ghostscript bug list:
https://bugs.launchpad.net/ubuntu/+source/ghostscript/+bug/172264

I've done some work to isolate the problem and it appears that it only occurs
when all of the following are true:
1.  The input file is a Postscript file generated by Acrobat from an encrypted
PDF file (see attached for an example).
2.  Ghostscript is built as a library (i.e. "make so").
3.  The input file is sent to Ghostcript via "- <filename".

From my testing it appears that the current head (r8406) continues to have this
problem.

Here's how to duplicate the problem (on my Ubuntu 7.10 AMD64 box under tcsh, ymmv):

  make XCFLAGS="-fPIC" XLDFLAGS="-fPIC" so
  setenv LD_LIBRARY_PATH sobin
  sobin/gsc -sDEVICE=ppmraw -sOutputFile=test.ppm - <./d01785-001
Comment 1 Marcos H. Woehrmann 2007-11-27 12:45:49 UTC
Created attachment 3583 [details]
d01785-001
Comment 2 Marcos H. Woehrmann 2007-11-27 12:55:58 UTC
Bumping the priority since this bug effects a large number of users and has high
visibility.
Comment 3 Till Kamppeter 2007-11-27 13:52:19 UTC
Especially note that distros tend to the library version of Ghostscript, due to
my packaging work Ubuntu, Debian, and Mandriva use the library version already.
Some programs like GSView require the library. For printing the input files are
usually piped into Ghostscript (in most cases by foomatic-rip or pstoraster) and
acroread 8.1.1 ships also with most current distros. So the occurrence of the
problem is ievitable.
Comment 4 Till Kamppeter 2007-11-27 13:53:29 UTC
A fix by a small patch is appreciated, as it can more easily be applied as an
update for a released Linux distribution than a new release of Ghostscript.
Comment 5 Ray Johnston 2007-11-27 17:12:33 UTC
The problem happens after the code:

%ADOBeginClientInjection: DocumentSetup Start "No Re-Distill"
%% Removing the following eleven lines is illegal, subject to the Digital
Copyright Act of 1998.
mark currentfile eexec
54dc5232e897cbaaa7584b7da7c23a6c59e7451851159cdbf40334cc2600
30036a856fabb196b3ddab71514d79106c969797b119ae4379c5ac9b7318
33471fc81a8e4b87bac59f7003cddaebea2a741c4e80818b4b136660994b
18a85d6b60e3c6b57cc0815fe834bc82704ac2caf0b6e228ce1b2218c8c7
67e87aef6db14cd38dda844c855b4e9c46d510cab8fdaa521d67cbb83ee1
af966cc79653b9aca2a5f91f908bbd3f06ecc0c940097ec77e210e6184dc
2f5777aacfc6907d43f1edb490a2a89c9af5b90ff126c0c3c5da9ae99f59
d47040be1c0336205bf3c6169b1b01cd78f922ec384cd0fcab955c0c20de
000000000000000000000000000000000000000000000000000000000000
cleartomark
%ADOEndClientInjection: DocumentSetup Start "No Re-Distill"

Apparently the 'cl' is getting swallowed by the eexec filter resulting in the
Error: /undefined in eartomark

Note that I was able to duplicate the problem on Windows with HEAD using:

cat bug_689577.ps | gswin32c -

Also on Windows, this works:   gswin32c bug_589577.ps

Comment 6 Ray Johnston 2007-11-27 17:26:18 UTC
The encoded sequence converts to:

2f63757272656e7464697374696c6c6572706172616d73207768657265207b20706f70202f7064666d61726b2077686572650a7b706f7020285468697320506f737453637269
70742066696c652077617320637265617465642066726f6d20616e20656e63727970746564205044462066696c652e5c6e29207072696e740a28526564697374696c6c696e67
20656e6372797074656420504446206973206e6f74207065726d69747465642e5c6e29207072696e740a7573657264696374202f71756974206765742065786563207d69667d
2069660a63757272656e7466696c6520636c6f736566696c650a1604804bdadf7f4a8d878826f56dff7415478907310809f3cee4a38cae4f

which displays as:

/currentdistillerparams where { pop /pdfmark where
{pop (This PostScript file was created from an encrypted PDF file.\n) print
(Redistilling encrypted PDF is not permitted.\n) print
userdict /quit get exec }if} if
currentfile closefile
&#9644;&#9830;ΗK&#9484;&#9600;&#8962;Jμηκ&&#8993;m t§Gλ     &#8804;&#9580;&#931;ϊξ«O

Comment 7 Marcos H. Woehrmann 2007-11-29 16:54:07 UTC
Created attachment 3587 [details]
simplified.ps

A much simplified test case that fails in the same way.,
Comment 8 Marcos H. Woehrmann 2007-11-30 06:59:41 UTC
The problem appears to be the mem->gs_lib_ctx->stdin_is_interactive flag being
set incorrectly.  The following hack allows the file to be read, however this
likely breaks other things:

Index: ziodevsc.c
===================================================================
--- ziodevsc.c  (revision 8416)
+++ ziodevsc.c  (working copy)
@@ -99,7 +99,7 @@
     if (mem->gs_lib_ctx->stdin_fn)
        count = (*mem->gs_lib_ctx->stdin_fn)
            (mem->gs_lib_ctx->caller_handle, (char *)pw->ptr + 1,
-            mem->gs_lib_ctx->stdin_is_interactive ? 1 : wcount);
+            mem->gs_lib_ctx->stdin_is_interactive ? wcount : wcount);  /* mhw */
     else
        count = gp_stdin_read((char *)pw->ptr + 1, wcount,
                      mem->gs_lib_ctx->stdin_is_interactive,


Comment 9 Marcos H. Woehrmann 2007-11-30 08:02:51 UTC
More details:

The significant routine appears to be s_stdin_read_process() in ziodevsc.c:

/* Read from stdin into the buffer. */
/* If interactive, only read one character. */
static int
s_stdin_read_process(stream_state * st, stream_cursor_read * ignore_pr,
                     stream_cursor_write * pw, bool last)
{
    int wcount = (int)(pw->limit - pw->ptr);
    int count;
    gs_memory_t *mem = st->memory;

    if (wcount <= 0)
        return 0;

    /* do the callout */
    if (mem->gs_lib_ctx->stdin_fn)
        count = (*mem->gs_lib_ctx->stdin_fn)
            (mem->gs_lib_ctx->caller_handle, (char *)pw->ptr + 1,
             mem->gs_lib_ctx->stdin_is_interactive ? 1 : wcount);
    else
        count = gp_stdin_read((char *)pw->ptr + 1, wcount,
                      mem->gs_lib_ctx->stdin_is_interactive,
                      mem->gs_lib_ctx->fstdin);

    pw->ptr += (count < 0) ? 0 : count;
    return ((count < 0) ? ERRC : (count == 0) ? EOFC : count);
}


The difference between Ghostscript running as a shared library and as a
standalone problem when using "- <filename" is that when running as a program
the gp_stdin_read() routine is called to read stdin and it is passed
mem->gs_lib_ctx->stdin_is_interactive which it ignores:

/* Read bytes from stdin, unbuffered if possible. */
int gp_stdin_read(char *buf, int len, int interactive, FILE *f)
{
    return read(fileno(f), buf, len);
}

Whereas when Ghostscript is a library the call to read stdin is to gsdll_stdin()
(which is what *mem->gs_lib_ctx->stdin_fn is set to) and it doesn't take
mem->gs_lib_ctx->stdin_is_interactive as a parameter but instead is called with
wcount set to 1.

So my comment #8 is partially correct, mem->gs_lib_ctx->stdin_is_interactive
isn't set incorrectly, it's just ignored in the standalone case.

So the question is why does the shared library need to pay attention to the
stdin_is_interactive flag when the standalone program ignores it?  Does this
comment explain why (from imainarg.c):

        case 0:         /* read stdin as a file char-by-char */
            /* This is a ******HACK****** for Ghostview. */
            minst->heap->gs_lib_ctx->stdin_is_interactive = true;
            goto run_stdin;


Comment 10 Marcos H. Woehrmann 2007-12-04 10:00:35 UTC
Based on Ray's suggestion I tested -_ instead of - to enable buffered reading
and it works.  This is a workaround, so I'll suggest this to Till but leave the
bug open.
Comment 11 Marcos H. Woehrmann 2007-12-04 21:34:14 UTC
Here's a diff -c example of the hack from comment #10:

*** LaserJet-6MP-foomatic.ppd.old       Tue Dec  4 11:04:07 2007
--- LaserJet-6MP-foomatic.ppd   Tue Dec  4 11:13:52 2007
***************
*** 95,101 ****
 *FoomaticIDs: HP-LaserJet_6MP hpijs
 *FoomaticRIPCommandLine: "gs -q -dBATCH -dPARANOIDSAFER -dQUIET -dNOPA&&
 USE -sDEVICE=ijs -sIjsServer=hpijs%A%B%C -dIjsUseOutputFD%Z -sOutputFi&&
! le=- -"
 *End

 *FoomaticRIPOption Model: enum CmdLine A 100
--- 95,101 ----
 *FoomaticIDs: HP-LaserJet_6MP hpijs
 *FoomaticRIPCommandLine: "gs -q -dBATCH -dPARANOIDSAFER -dQUIET -dNOPA&&
 USE -sDEVICE=ijs -sIjsServer=hpijs%A%B%C -dIjsUseOutputFD%Z -sOutputFi&&
! le=- -_"
 *End

 *FoomaticRIPOption Model: enum CmdLine A 100
Comment 12 Till Kamppeter 2007-12-06 04:29:31 UTC
To not need to change all entries in the Foomatic database one by one, I have
simply modified the foomatic-gswrapper (the general Ghostscript problem
workaround layer of Foomatic) to replace any expression for stdin as the input
file for Ghostscript ny '-_'. Get the new version of the foomatic-gswrapper from

http://www.openprinting.org/foomatic-gswrapper

and replace your foomatic-gswrapper with it (usually in /usr/bin)

This makes all print queues with Foomatic-based PPDs (for example HP inkjets and
PCL lasers) printing correctly again.

If your printer uses a CUPS raster driver, the /usr/lib/cups/filter/pstoraster
needs to be patched. Replace the line

ifile="-"

by

ifile="-_"

(line 54 in current version). I have done this in the Ghostscript SVN repository
as rev 8423.

If you are using a driver of Rick Richardson's foo2zjs suite
(http://foo2zjs.rkkda.com/, HP LaserJet 10xx, P10xx, M1005 MFP, Color LaserJet
1500, 1600, 2600n, Konica Minolta magicolor DL/MF series, Samsung CLP-300/600,
Xerox Phaser 6110, Lexmark C500n) run the following command as root to patch all
the Ghostscript wrapper scripts of foo2zjs:

perl -p -i -e 's/(GAMMAFILE )- /\1-_ /' /usr/bin/foo2*wrapper

I have applied all this in Ubuntu Hardy now.
Comment 13 Till Kamppeter 2007-12-07 10:56:16 UTC
For foo2zjs the workaround was now applied upstream, too.
Comment 14 Till Kamppeter 2007-12-08 14:52:51 UTC
A fix of this bug is really needed, as workarounds cannot be applied everywhere.
Especially the closed-source drivers from Samsung call Ghostscript (with "-" as
input) out of a closed-source executable. Here one cannot do quick workarounds
as I have shown in my previous comments. See also the complaint of the user
"lunomad" in the Ubuntu bug report.
Comment 15 Sammy Umar 2007-12-08 16:41:19 UTC
Can we get a nod whether a fix for this in ghostscript is coming or not?
Many applications like kghostview and evince are failing as well. I made
a small fix for kghostview (replacing - with -_ in one location) but if
ghostscript is going to be fixed we will have to take all these out again.
It would be nice to know. Thanks.
Comment 16 Ray Johnston 2007-12-08 16:44:59 UTC
Till wrote in the previous comment:
"A fix of this bug is really needed, as workarounds cannot be applied everywhere.
Especially the closed-source drivers from Samsung call Ghostscript (with "-" as
input) out of a closed-source executable."

Since GPL doesn't allow closed source (isn't being able to fix it yourself part
of the point of GPL), this looks like a violation of GPL and thus a violation
of Artifex's license of Ghostscript under GPL. I'm not a lawyer, but I will
forward this to the appropriate people at Artifex Software.

----

As far as fixing the bug, it's still open and will get fixed.
Comment 17 Ray Johnston 2007-12-08 16:50:38 UTC
A comment on needing to take out the '-_' ...

The '-' assumes that the input needs to be interactive and shouldn't be
buffered (needs to read 1 character at a time). The '-_' uses larger buffers from
stdin and so it generally is more efficient anyway.
Comment 18 Marcos H. Woehrmann 2007-12-08 19:25:36 UTC
I have a couple of suggestions as to how we can fix this without having to delve
into the atream code:

1.  Replace /usr/bin/gs with the standalone gs instead of the stub that calls
the library.

2.  Have the /usr/bin/gs stub scan the command line and replace '-' with '-_'
before calling the library Ghostscript.  

Both to these shouldn't break any existing code.  Since the standalone
Ghostscript has always had '-' mean buffered input anyone calling /usr/bin/gs
shouldn't be expecting anything else.
Comment 19 Alex Cherepanov 2007-12-08 22:40:52 UTC
A patch that reduces the buffer in eexecDecode filter has been committed
as a rev. 8428. See:
http://ghostscript.com/pipermail/gs-cvs/2007-December/008011.html

Regression testing shows no differences.

The sample file is incorrect. It has to few 0's than specified in
PLRM. The affected fragment is inserted into PS files generated by
Adobe Acrobat from PDF files with usage restrictions. So the fragment
doesn't change between files and the proposed solution should be
robust enough.

The buffer size of 132 has been selected from a middle of small window that
fixes the bug but doesn't cause regression in comparefiles/fonttest.pdf.
Detection of EOF after seeing a run of 0's is worth to note as an alternative.

Comment 20 Sammy Umar 2007-12-09 08:45:59 UTC
Should one keep the previous changes to cups etc. that replace - with -_ ?
Comment 21 Till Kamppeter 2007-12-09 09:27:53 UTC
An addition to my comment #14: A possible workaround is to replace Samsung's
closed-source driver ny the open-source driver SpliX, which supports most not
too old Samsung printers. From Samsung's driver use only the scanner driver if
you have an MF device. The SpliX driver (see http://www.openprinting.org/) is a
pure CUPS Raster driver which does not call Ghostscript by itself, my
workarounds from comment #12 are sufficient.

About comment #16: There is no GPL violation. Samsung's drivers are not
published under the GPL.

About comment #17: I will keep all my workarounds in place, not only because it
takes time until everyone will have a fixed Ghostscript but also as buffered
input is better for the performance.

About comment #18: The suggestion (2) can be implemented easily: Replace your
/usr/bin/foomatic-gswrapper by the newest one from

http://www.openprinting.org/foomatic-gswrapper

Rename /usr/bin/gs to /usr/bin/gs.orig and rename /usr/bin/foomatic-gswrapper to
/usr/bin/gs. Then edit /usr/bin/gs replacing 'my $gspath = "gs";' by 'my $gspath
= "gs.orig";'. Now every call of "gs", including calls by pstoraster and by
closed-source drivers, has all workarounds and fixes from foomatic-gswrapper
applied, especially the "-_" as input file.

About comment #19: As the fix is a really simple patch, I recommend to every
distro package maintainer to apply this patch without waiting for the next
official release of Ghostscript, and even apply this patch as an update for
already released versions of the distros.

Here is the patch:

----------
Modified: trunk/gs/src/seexec.c
===================================================================
--- trunk/gs/src/seexec.c 2007-12-08 13:57:53 UTC (rev 8427)
+++ trunk/gs/src/seexec.c 2007-12-09 06:33:00 UTC (rev 8428)
@@ -215,8 +215,10 @@
  * so that it will stay under the limit even after adding min_in_size
  * for a subsequent filter in a pipeline. Note that we have to specify
  * a size of at least 128 so that filter_read won't round it up.
+ * The value of 132 is small enough for the sample file of the bug 689577 but
+ * still sufficient for comparefiles/fonttest.pdf .
  */
 const stream_template s_exD_template = {
- &st_exD_state, s_exD_init, s_exD_process, 8, 200,
+ &st_exD_state, s_exD_init, s_exD_process, 8, 132,
     NULL, s_exD_set_defaults
 };
----------


Comment 22 Till Kamppeter 2007-12-09 09:30:01 UTC
Sammy, I recommend to keep the workarounds in place as buffered input improves
the performance.
Comment 23 Gustavo Homem 2009-05-06 15:38:46 UTC
Although the 200 -> 132 patch solves the problem for simplified.ps I have a PDF
for which the problem is not solved.

We get

"Error: /undefined in ec"

I can send the file privately.
Comment 24 Gustavo Homem 2009-05-06 15:39:56 UTC
This bug did not exist in ghostscript 8.15-22.
Comment 25 Alex Cherepanov 2009-05-07 04:46:56 UTC
Created attachment 5002 [details]
pdfteste-hack.ps

Reduced PS file that has Adobe startup code only. The file displays blank page.


The bug can be reproduced by:
  gswin32c - <pdfteste-hack.ps
Comment 26 Gustavo Homem 2009-07-02 07:52:52 UTC
Seems that this problem applies to all PDFs with "security restrictions" (even
if printed is not restricted).

The bug is present on ghostscript 8.60-55 but not on (for example) 8.15-22 and
7.07-25.

Is this expected to be fixed inside ghostscript?
Comment 27 Masaki Ushizaka 2009-08-11 01:10:52 UTC
Reproduced pdfteste-hack.ps from #25 with r9948 on both Windows XP Pro SP3 + VS2008 Express and 
Windows 2000 Pro SP4 + VS6 SP6.  Did not reproduce on Mac OS X.  Looks like windows only problem.
Replacing '-' with '-_' removes error, this can be used as a workaround.
Comment 28 Masaki Ushizaka 2009-08-11 04:44:09 UTC
My mistake.  Please forget 'Did not reproduce on Mac OS X.  Looks like windows only problem.' part in 
above my comment.  I didn't try it using shared object.
Comment 29 Alex Cherepanov 2009-08-13 12:08:58 UTC
In hex form of eexec stream, break out of reading loop and try to interpret
the accumulated data when a whitespace character is encountered. Skip whitespace
characters when the control returns to /eexecDecode filter.

Normally, eexec stream is followed by a large number of 0's to compensate
for read-ahead effects. The code fragment that Adobe Acrobat uses to prevent
re-distilling of the file has no trailing 0's at all. This patch tries to guess
the end of eexec stream after every whitespace character.

The following patch has been committed as a rev. 9989.
http://ghostscript.com/pipermail/gs-cvs/2009-August/009693.html
Regression testing shows no differences.