Как справиться с переполнением стека? - PullRequest
1 голос
/ 02 ноября 2011

Я пытаюсь исправить обработку ошибок в моем интерпретаторе postscript, и мне трудно найти способы выполнения обработчиком, когда один из стеков заполнен.

Используемая мной процедура обработчика уровня postscript - это «стандартная» процедура, описанная в 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

Таким образом, ему требуется место в стеке операндов (для словаря $ error, имен и прочего) и в стеке выполнения (для тел процедур, если они выполнены). Так что, если какой-либо из стеков переполнен, откуда это место должно появиться?

Сначала я попытался решить задачу execstackoverflow, поскольку execstack использует меньше операторов, чем стек операндов. Я определил размер буфера

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

которые все операторские функции "exec" добавляют к проверке пробела. Например. вот оператор exec.

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

И тогда цикл интерпретатора проверяет наличие гораздо меньшего размера (поэтому он не вызывает даже больше ошибок при попытке запустить обработчик).

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

Но это не сработает (SEGFAULT), пока я не очищу некоторое пространство в обработчике ошибок уровня C, как раз перед тем, как он выталкивает (планирует) обработчик PS в 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();
    }
...

Но теперь я выбросил ребенка с водой! Эти записи на вершине стека могут быть просто важной информацией для исправления ошибки, и я просто выбросил их в пропасть.

Кто-нибудь может предложить лучший способ сделать это?

1 Ответ

1 голос
/ 02 ноября 2011

Не зная слишком много о вашем коде, я думаю, что создание стека ошибок, который может сам себя расширять, было бы решением.

...