Bug 689535 - Print PDF-> PS ok, PS -> PDF not ok
Summary: Print PDF-> PS ok, PS -> PDF not ok
Status: NOTIFIED FIXED
Alias: None
Product: Ghostscript
Classification: Unclassified
Component: PDF Writer (show other bugs)
Version: 8.60
Hardware: PC Windows XP
: P4 normal
Assignee: Alex Cherepanov
URL: http://www.belldandy.idv.hk/GS/debugM...
Keywords:
: 689809 689992 (view as bug list)
Depends on:
Blocks:
 
Reported: 2007-10-30 01:39 UTC by Fsdfl5463
Modified: 2008-12-19 08:31 UTC (History)
2 users (show)

See Also:
Customer:
Word Size: ---


Attachments
PS file created by Acrobat 8.1.0 from the sample PDF file (741.03 KB, application/postscript)
2007-10-30 08:23 UTC, Alex Cherepanov
Details
patch (566 bytes, patch)
2007-10-30 08:32 UTC, Alex Cherepanov
Details | Diff
Minimal file to reproduce the problem (291 bytes, application/postscript)
2008-01-08 01:27 UTC, Ken Sharp
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Fsdfl5463 2007-10-30 01:39:52 UTC
Source PDF link: http://www.belldandy.idv.hk/GS/SourceTempFile1030_0222381.pdf
Source PDF Producer: Acrobat Distiller 7.0 (Windows)
Debug Message:http://www.belldandy.idv.hk/GS/debugMessage.txt

Step 1:
Use Adobe Reader 8.1.1 read SourceTempFile1030_0222381.pdf, print to PS file.
No Error.

Step 2:
PS file -> PDF by GSWin32c, fail. 

Debug message:
**** DSC comment: /Page
<< /PageNum 1 /DSC_struct -dsc_data_struct- >> (debug message stop in here)
Comment 1 Alex Cherepanov 2007-10-30 08:23:21 UTC
Created attachment 3507 [details]
PS file created by Acrobat 8.1.0 from the sample PDF file
Comment 2 Alex Cherepanov 2007-10-30 08:32:04 UTC
Created attachment 3508 [details]
patch

Work around a possibility that t_struct ref can be constructed from a NULL
pointer.

I don't yet know where such ref's are broken and the bug should be fixed
elsewhere. Such ref's can be easily found by checking addressability of the
pointer in make_struct macro.
Comment 3 Ray Johnston 2007-10-30 09:52:34 UTC
This appears to be a pdfwrite issue, so assigning to Ken
Comment 4 Fsdfl5463 2007-12-05 01:43:48 UTC
When I use ghostscript version 8.61

Step 1:
Use Adobe Reader 8.1.1 read SourceTempFile1030_0222381.pdf, print to PS file.
No Error. GsView 4.9 can open it.

Step 2:
PS file -> PDF by GSWin32c, fail. 

Debug message:
**** DSC comment: /Page
<< /DSC_struct -dsc_data_struct- /PageNum 1 >> (debug message stop in here)
Comment 5 Ken Sharp 2007-12-21 09:26:08 UTC
Help ? :-(

I'm at a bit of a loss with this one. While it only seems to go wrong with
pdfwrite, I can't (at the moment) see why this is the case. Alex's patch works
round the problem, but it doesn't address the underlying issue.

The job sets up a Pattern with a revolting PaintProc (it draws tiny imagemasks,
I think to create a  logo).

Anyway, the problem exhibits inside the PostScript interpreter. It sets a
colour, determines its a pattern colour, installs a capture device (I think) and
then exits with an error code which causes GS to run the PaintProc. The problem
'seems' to occur while executing the PaintProc. But it might be something
pdfwrite is doing, the PaintProc takes an age to execute in the interpreter and
I haven't found a way to isolate the specifics of the problem, whether its the
PaintProc causing the problem, or whether pdfwrite is pushing another exec.

Does anyone have any hints on how to debug this ?

Comment 6 leonardo 2007-12-21 21:00:20 UTC
I believe the bug is wrongly assigned. I'll check with Henry.
Comment 7 Ken Sharp 2007-12-22 01:33:22 UTC
Well it does only happen with pdfwrite, so I think its entirely possible
(perhaps even likely) that pdfwrite is causing the execstack which fails. My
problem is that it takes forever to step through the initial PaintProc execution
in the PostScript interpreter. (BTW it seems the pattern is used to draw dashed
lines...)

I suspect that there's some pattern madness going on in pdfwrite, after the
pattern has been captured, but I don't know enough to put a sensible breakpoint
in place.

Any clues would be much appreciated ;-)

Comment 8 Ray Johnston 2007-12-22 09:36:40 UTC
I don't know if this helps, and I apologize in advance if you already knew all
of this and it's way to basic.
---
You can turn on interpreter tracing, or other -Z debug actions from within
PostScript using .setdebug so you don't need to have -ZI on the whole time.
For example, to turn on interpreter tracing, use:
   (I) true .setdebug
and to turn it off later,
   (I) false .setdebug

I also sometime through in a "() false .setdebug" in PS to allow me to hit a
breakpoint in zsetdebug.

The normal (not big pattern approach) is to run the PaintProc after setting a
'pattern accumulator' device (see src/gxpcmap.c:gx_pattern_accum_alloc).
The PaintProc is actually 'run' from zpcolor.c:pattern_paint_prepare which
"pushes" the PaintProc on to the execstack (near the end).

It also pushes the 'closure' "pattern_paint_finish" that does the cleanup.

Thus, you should see the pattern_paint_prepare followed by pattern_paint_finish
when the PaintProc finishes.

Igor can explain the big_pattern (currently bitmaps > 1Mb) logic, but basically
it installs a 'clist device' as the pattern accumulator.

The pdfwrite device modifies this quite a bit because it supports it's own
'pattern_manage__*' functions. Since the problem is specific to pdfwrite,
looking through the src/gdevpdfi.c and associated logic is needed. Once again,
Igor would be the one to explain this.
Comment 9 leonardo 2007-12-22 23:22:27 UTC
Regarding comment #8 : When developing big patterns, I did not do anything 
special to pdfwrite. The latter implements its own pattern stream accumulator. 
The clist-based accummulator must not run with pdfwrite.
Comment 10 leonardo 2007-12-22 23:24:31 UTC
regarding Cpomment #2 : First need to figure out whether NULL struct pointer 
must be a legal case or not. If yes, it's Alex's job, since he owns 
zcontrol.c . 
Comment 11 Ken Sharp 2008-01-02 07:22:29 UTC
Thanks for the hints everyone. The problem appears to be caused by the fact that
the pattern paints an image, and the image is in a CIEBasedABC colour space.

If I alter the image dictionary (in the pattern PaintProc) to use DeviceRGB
instead, the problem disappears. Since the image is in fact monochrome, this
gives the correct result.

So now I have to find out what pdfwrite is doing wrong to create an empty frame
when evaluating a CIEBased colour space in a Pattern context. Might take a while
but I have a starting point. Thanks again.

Comment 12 Ken Sharp 2008-01-08 01:27:00 UTC
Created attachment 3681 [details]
Minimal file to reproduce the problem

I believe I now fully understand this issue, and its not specifically related
to pdfwrite. As a result I'm assigning it to Alex for a final decision on what
to do. 

The following detailed explanation is intended for Alex, and anyone else
interested :-)

The issue is to do with devices handling patterns as high-level objects, which
is why it affects pdfwrite (which can handle patterns itself) but not regular
rendering. In zpcolor.c, pattern_paint_prepare(), there are two control paths,
one for devices which handle patterns as high-level objects, and one for
devices which don't. If the device can't handle high level objects, we install
a pattern accumulation device.

In this case, the flag internal_accum is set, we create the pattern accumulator
device and open it:

    if (internal_accum) {
	gs_memory_t *storage_memory = gstate_pattern_cache(pgs)->memory;

	pdev = gx_pattern_accum_alloc(imemory, storage_memory, pinst,
"pattern_paint_prepare");
	if (pdev == 0)
	    return_error(e_VMerror);
	code = (*dev_proc(pdev, open_device)) ((gx_device *) pdev);
...
...
}

Later the two control paths rejoin and we put some objects on the execution
stack:

    push_mark_estack(es_other, pattern_paint_cleanup);
    ++esp;
    make_istruct(esp, 0, pdev);

Now notice that we construct the structure on esp using pdev, but we *don't*
create pdev if we can handle patterns, so its left as NULL and we end up
pushing an empty t_struct.

Leo's question in comment 10 is whether this is legal, the answer appears to be
yes, but its debatable. 

In pattern_paint_finish we do this:

    gx_device_forward *pdev = r_ptr(esp - 1, gx_device_forward);

    if (pdev != NULL) {
	gx_color_tile *ctile;
	int code = gx_pattern_cache_add_entry((gs_imager_state *)igs,
					  pdev, &ctile);

That is, if the structure *isn't* NULL we do something with it, we ignore it if
it is NULL. Either way we then do this:

    esp -= 3;

Removing all the objects from the execution stack that we added. Notice that
the structure we pushed onto the execution stack isn't actually 'executed', its
just data used by the pattern handler.

Now, all this works just fine in normal practice, however the job here uses a
CIEBased colour space, and being from an Adobe application it tries to set the
ColorRendering. Since we don't implement a ColorRendering resource category,
this causes an error (handled in a stopped context).

The default error handler uses execstack, and this is where the actual error
finally occurs, because execstack can't handle the empty structure.

I have no idea how common the practice of putting device structures on the
execution stack is, so I can't judge whether this is expected behaviour. If it
is we should adopt Alex's initial patch and modify execstack & friends to
handle the situation. Otherwise we should adopt whatever is the 'correct'
method for dealing with this kind of argument passing and modify the pattern
handling code appropriately. My guess is that we should just modify the
execstack stuff.

For ease of further investigation I've attached a much simplified job, the
PaintProc for the pattern has a single line which is commented out. Remove the
comment and run with a device capable of high-level pattern handling to
generate the error.
Comment 13 Alex Cherepanov 2008-04-30 18:18:22 UTC
*** Bug 689809 has been marked as a duplicate of this bug. ***
Comment 14 Alex Cherepanov 2008-07-29 12:20:47 UTC
The patch from the comment #2 is committed as a rev. 8901.
Even if NULL pointers to structures are invalid, a crash in execstack
is clearly undesirable.

This patch is similar to a protection measure in modern printf(),
which prints NULL instead of crashing when it receives NULL pointer.

Besides, NULL is a valid pointer value in C and it should be possible
to pass it through PostScript level and expect that it is compatible
with the error handler.
Comment 15 Alex Cherepanov 2008-08-05 08:10:16 UTC
*** Bug 689992 has been marked as a duplicate of this bug. ***