c: поймать segfault в exec (), который был запущен в дочернем процессе - PullRequest
2 голосов
/ 07 сентября 2011

EDIT:

Я пытаюсь написать простую проверку дыма, в которой проверяются все параметры и приемлемые параметры.

Я использовал popen () для запуска программы, которую нужно протестировать. Использование этого подхода не работает, потому что, если процесс умирает с сигналом (SIGINT, SIGSEGV ...), канал из popen () не сообщает мне, что произошло.

Написание обработчика сигналов не помогло, так как popen создает новый процесс, который получает сигналы, но не мой тест.

Благодаря ответам я использовал pipe (), fork () и execv () для создания своей собственной popen () - версии.

Когда программа теперь выполняет segfaults, возникает проблема с тем, что канал бесполезен (странное поведение, вызванное чтением -> блокирует процесс, пока я не отправлю сигкилл родителю!)

Чтобы избежать этого, я пробовал разные вещи, и мое решение заключается в следующем (это просто, но мне потребовалось некоторое время, чтобы понять это). так вот мой пример кода:

static int child_dead = 0;

void sigaction_sigchld(int signal) { /* Child died */
    child_dead = 1;
}

int main(int argc, char *argv[], char *env[])
{
    char *crashing_program = "/program_path/and_name";
    int ret;
    int byte;

    pid = fork();

    if(pid == 0) /* Child */
    {
        execve(crashing_program, argv, env);

        /* if execve returns that it mus have failed! */
        fprintf(stderr, "Exec failed\n");
        _exit(-1);
    } else /* Parent */
    {
        if(!child_dead)
        {
            byte = read(pipe_out[1], line, BUFFSIZE);
            if(!byte){
                perror("Smoketest:Line:xxx");
            } else
            {
                fprintf(stdout, line);
            }
        }
        wait(&child_status);
        /*
          check if the child died with SIGSEGV etc
        */
    }

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

И последнее, но не менее важное: конечно, используя этот метод, возможно, невозможно выполнить какую-либо очистку.

Приветствие.

1 Ответ

7 голосов
/ 07 сентября 2011

См. Документацию для waitpid(2). Есть несколько макросов, которые вы можете использовать для проверки того, как дочерний процесс был прерван. В частности, вы можете использовать WIFSIGNALED() и WTERMSIG(), чтобы проверить, был ли дочерний процесс завершен сигналом, и если да, то какой сигнал:

int status = pclose(...);
if (WIFSIGNALED(status))
{
    // It was terminated by a signal
    if (WTERMSIG(status) == SIGSEGV)
    {
        // It was terminated by a segfault
    }
}

Редактировать: Как указано в комментариях, вы бы предпочли использовать fork и exec, а затем использовать waitpid(2) для правильного обновления статуса.

...