После Segfault: есть ли способ, чтобы убедиться, что указатель все еще действителен? - PullRequest
0 голосов
/ 09 декабря 2010

Я планирую создать механизм ведения журнала / трассировки, который записывает адрес (const char*) строковых литералов в кольцевой буфер.Эти строки находятся в сегменте данных только для чтения и создаются препроцессором с __function__ или __file__.

Вопрос : возможно ли проанализировать это кольцо?содержимое буфера после Segfault, если все указатели действительны?Под «действительным» я подразумеваю, что они указывают на отображенную область памяти, и разыменование не вызовет ошибку сегментации.

Я работаю с Linux 2.6.3x и GCC 4.4.x.

С уважением,

Чарли

Ответы [ 4 ]

2 голосов
/ 10 декабря 2010

Обычный способ проверить, не приведет ли разыменование области памяти к segfault, - это использовать read() или write(). Например, чтобы убедиться, что первые 128 байтов, на которые указывает ptr, безопасны для чтения:

int fd[2];
if (pipe(fd) >= 0) {
    if (write(fd[1], ptr, 128) > 0)
        /* OK */
    else
        /* not OK */
    close(fd[0]);
    close(fd[1]);
}

(write() вернет EFAULT, а не повысит сигнал, если область не читается).

Если вы хотите протестировать более PIPE_BUF байт за раз, вам нужно читать и отбрасывать со стороны чтения канала.

2 голосов
/ 09 декабря 2010

Я думаю, что подход, который вы ищете, заключается в обработке сигнала SIGSEGV через sigaction.

void handler(int, siginfo_t *info, ucontext_t *uap)
{
   /* Peek at parameters here...  I'm not sure exactly what you want to do. */
}

/* Set up the signal handler... */

struct sigaction sa, old_sa;
memset(&sa, 0 sizeof(sa));

sa.sa_sigaction = handler;
sa.sa_flags = SA_SIGINFO;

if (sigaction(SIGSEGV, &sa, &old_sa))
{
   /* TODO: handle error */
}

Обратите внимание, что перехват SIGSEGV в вашем собственном процессеэто немного странноПроцесс, вероятно, находится в плохом состоянии, из которого невозможно восстановить.Действия, которые вы сможете выполнить в ответ на это, могут быть ограничены, и, скорее всего, удаляемый процесс - это хорошо.

Если вы хотите, чтобы он был немного более стабильным, естьsigaltstack вызов, который позволяет вам указать буфер альтернативного стека, так что, если вы полностью закрепили свой стек, вы все равно можете обрабатывать SIGSEGV.Чтобы использовать это, вам нужно установить SA_ONSTACK в sa.sa_flags выше.

Если вы хотите ответить на SEGV из-за безопасности другого процесса (таким образом изолируя себя от плохо функционирующего кода segfaulting и делая егочтобы вы не потерпели крах при проверке), вы можете использовать ptrace.Этот интерфейс сложен, имеет много непереносимых частей и в основном используется для написания отладчиков.Но вы можете делать с ним великие дела, такие как чтение и запись памяти и регистров процесса, а также изменять его выполнение.

1 голос
/ 09 декабря 2010

Конечно, если стек или другая память, на которую вы полагаетесь, повреждены, то могут быть проблемы, но это верно для любого кода.

Предполагая, что нет проблем со стеком или другимипамяти, на которую вы полагаетесь, и при условии, что вы не вызываете никакие функции, такие как malloc(), которые не безопасны для асинхронного сигнала , и, если вы не пытаетесь вернуться из обработчика сигнала, тогдане будет проблем с чтением или записью буфера из вашего обработчика сигналов.

Если вы пытаетесь проверить, является ли конкретный адрес действительным, вы можете использовать системный вызов, такой как mincore()и проверьте результат ошибки.

0 голосов
/ 09 декабря 2010

Как только вы получили segfault, все ставки отменены. Указатели могут быть действительными или они могут быть повреждены. Ты просто не знаешь. Возможно, вы сможете сравнить их с действительными значениями, или указатель на сам кольцевой буфер может быть поврежден. В этом случае вы, вероятно, получите мусор.

...