Search code examples
cerror-handlingstack-overflowinterpreterpostscript

How to handle a stackoverflow?


I'm trying to fix up the error handling in my postscript interpreter, and I'm having difficulty coming up with ways for the handler to execute when one of the stacks is full.

The postscript-level handler procedure I'm using is the "standard" one described in Frank Merritt Braswell, Inside Postscript.

/.error {
    //$error exch /errorname exch put
    //$error exch /command exch put
    //$error /newerror true put
    //$error /errorname get /VMerror ne {
        //$error /ostackarray get null eq {
            //$error /estackarray 250 array put
            //$error /ostackarray 6000 array put
            //$error /dstackarray 30 array put
        } if
        count
        //$error /ostackarray get exch 0 exch getinterval astore
        //$error exch /ostack exch put
        //$error /dstack //$error /dstackarray get dictstack put
        //$error /estack //$error /estackarray get execstack
        dup length 2 sub 0 exch getinterval put
        //$error /ostack get aload pop
    } if
    //$error /initializing get {
        handleerror
    } if
    interrupt
} def

So it needs space on the operand stack (for the $error dictionary and names and stuff) and execution stack (for the procedure bodies, if executed). So if either stack has overflowed, where is this space supposed to come from?

I attempted to tackle the execstackoverflow first, since fewer operators use the execstack than use the operand stack. I defined a "buffer" size

#define ERRDEPTH 5 /*space reserved on execstack for error handling*/

which all "exec" operator functions add to the space check. Eg. here's the exec operator.

void Aexec(state *st, object x) { (void)st;
    if ((tes-es)+1+ERRDEPTH >= ESSIZE) error(st,execstackoverflow);
    pushe(x);
}

And then the interpreter loop checks for a much smaller size (so it doesn't trigger even more errors while trying to run the handler).

bool eval (state *st) {
    ...
    /* room to work? */
    if ((tes-es) + 2 /*+ ERRDEPTH*/ > ESSIZE) error(st,execstackoverflow);
    ...

But it doesn't work (SEGFAULT) unless I clear up some space in the C-level error handler, just before it pushes (schedules) the PS handler on the execstack.

...
    if (e == execstackoverflow) { /* make some room! */
        (void)pope(); (void)pope(); (void)pope(); (void)pope(); (void)pope();
        (void)pope(); (void)pope(); (void)pope(); (void)pope(); (void)pope();
    }
...

But now I've thrown the baby out with the bathwater! Those entries on the top of the stack might just be the crucial information for fixing the error, and I've just tossed them into the abyss.

Can anyone suggest a better way of going about this?


Solution

  • Without knowing too much about your code, I would imagine creating an error stack that can expand itself would be the solution.