Exec функция в c не возвращает -1, когда она должна - PullRequest
0 голосов
/ 28 ноября 2018

Я использую функцию execv для запуска программы с именем code.x.У code.x есть часть, где он гарантирует свою неудачу с помощью Assertion.Мой код, который запускает execl:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h> 
#include <errno.h>
#include <string.h>

int main()
{
    pid_t pid;
    char *args[] = { "./code.x",NULL };
    pid = fork();
    if (pid > 0) {
        wait(NULL);
        printf("%s\n", strerror(errno));
        printf("done\n");
    }
    else if (pid == 0) {
        printf("%s\n", strerror(errno));
        execv(args[0], args);
        printf("should fail");
    }
    else {
        printf("forkfail");
    }
    return 1;
}

код печатает

Success
code.x: code.c:15: main: Assertion '0 == 1' failed.
Success
done

«должен произойти сбой» никогда не печатается и WEXITSTATUS (состояние) показывает, что состояние выхода равно 0.

Ответы [ 4 ]

0 голосов
/ 28 ноября 2018

Семейство функций Exec заменяет существующий образ процесса новым образом процесса.Вот почему требуется выполнить разветвление перед порождением другого процесса, поскольку текущий выполняемый процесс полностью заменен, включая счетчик программ, который отслеживает выполнение следующей инструкции.

printf("should fail");

никогда не выполняетсяпоскольку в тот момент, когда вы вызвали execv(args[0], args), программный счетчик был перемещен для выполнения args [0], что оставило позади путь выполнения, который привел бы к этому оператору печати. ​​

Exec возвращает -1 при условии, чтопри замене изображения произошла ошибка, и она не имеет абсолютно никакого отношения к возвращаемому значению выполняемой программы.Это связано с тем, что после вызова Exec два процесса вообще не координируются друг с другом.Помните: команда fork() создала новое адресное пространство, что означает, что эти процессы теперь выполняются в отдельных доменах в отдельных исполняемых файлах.

Может помочь некоторая документация:

http://man7.org/linux/man-pages/man3/exec.3.html

Надеюсь, это помогло.

0 голосов
/ 28 ноября 2018

Семейство функций exec заменяет вызывающий процесс новой программой в исходном состоянии, загруженной из исполняемого файла.Они могут потерпеть неудачу только в случае сбоя этой замены, например, из-за того, что запрошенный файл не существует или вызывающий пользователь не имеет прав доступа к нему / выполнить его.

Если ошибка подтверждения в программе ./code.x, которую вы вызываетеслучается, это далеко за пределами точки, где execv мог потерпеть неудачу;на этом этапе исходное состояние программы, в котором было выполнено execv, больше не существует, поскольку оно уже было заменено.Родительский процесс увидит, что он выходит через функцию wait -семейства, и может проверить состояние, сообщенное функцией wait -family, чтобы определить, почему он вышел.

0 голосов
/ 28 ноября 2018

exec* функции завершаются успешно, если программа запускается.Ваша программа запустилась.

Ошибка подтверждения приводит к тому, что программа прерывает , завершается с сигналом .Страница руководства Linux wait (2) объясняет, что:

WEXITSTATUS(wstatus)

возвращает состояние выхода дочернего элемента.Он состоит из наименее значащих 8 битов аргумента состояния, который дочерний элемент указал в вызове exit(3) или _exit(2) или в качестве аргумента для оператора возврата в main(). Этот макрос следует использовать только в том случае, если WIFEXITED вернул true.

Если вы не проверили, что WIFEXITED(status) имеет значение true, тогда WEXITSTATUS(status) означает мусор.

Вместо этого отметьте WIFSIGNALED(status) и, если оно истинно, получите сигнал - WTERMSIG(status), который должен быть равен SIGABRT.

0 голосов
/ 28 ноября 2018

execv успешно выполнил свою работу.Процесс ./code.x выполняется, затем завершается из-за подтверждения g.

Семейство функций exec не заботится о возвращаемом значении процесса.Как только процесс запускается, вызывающий процесс эффективно завершается и исчезает.

Exec вернется, только если по какой-то причине процесс вообще не может быть запущен . В частности, только эти ошибки (будет взято из ex-man и вернет errno к одному из следующих значений:

  • E2BIG Общее количество байтов в среде (envp) и аргументсписок (argv) слишком велик.

  • EACCES Отказано в разрешении на поиск для компонента префикса пути имени файла или имени интерпретатора сценария.(См. Также path_resolution (7).)

  • EACCES Файл или интерпретатор сценария не является обычным файлом.

  • EACCES Отказано в разрешении на выполнение файла, скрипта или интерпретатора ELF.

  • EACCES Файловая система смонтирована noexec.

  • EAGAIN (начиная с Linux 3.1) Изменив свой реальный UID с помощью одного из вызовов set * uid (), вызывающая сторона была - и теперь все еще - выше своего ограничения ресурса RLIMIT_NPROC (см. setrlimit (2)).Для более подробного объяснения этой ошибки см. NOTES.

  • EFAULT имя файла или один из указателей в векторах argv или envp указывает за пределы доступного адресного пространства.

  • EINVAL Исполняемый файл ELF имел более одного сегмента PT_INTERP (т. Е. Пытался назвать более одного интерпретатора).

  • EIO I /Произошла ошибка.

  • EISDIR В качестве каталога использовался интерпретатор ELF.

  • ELIBBAD Переводчик ELF не был в распознанном формате.

  • ELOOP При разрешении имени файла или имени скрипта или интерпретатора ELF обнаружено слишком много символических ссылок.

  • ELOOPМаксимальный предел рекурсии был достигнут во время рекурсивной интерпретации сценария (см. «Сценарии переводчика» выше).До Linux 3.8 в этом случае создавалась ошибка ENOEXEC.

  • EMFILE Достигнуто ограничение на число обработчиков дескрипторов открытых файлов.

  • ENAMETOOLONG имя файла слишком длинное.

  • ENFILE Достигнуто общесистемное ограничение на общее количество открытых файлов.

  • ENOENT Файл с именем файла или сценария или интерпретатора ELF не существует, или не найдена общая библиотека, необходимая для файла или интерпретатора.

  • ENOEXEC Исполняемый файл не в распознанном формате, имеет неправильную архитектуру или имеет другую ошибку формата, которая означает, что он не может быть выполнен.

  • ENOMEM Недостаточно памяти ядра было доступно.

  • ENOTDIR Компонент префикса пути имени файла или сценария или интерпретатора ELF не является каталогом.

  • EPERMФайловая система смонтирована nosuid, пользователь не является суперпользователем, а файл имеет set-user-ID or бит набора идентификаторов группы установлен.

  • EPERM Процесс отслеживается, пользователь не является суперпользователем, и файл имеет set-user-ID или set-group-ID установлен бит.

  • EPERM Приложения с «немыми возможностями» не получат полный набор разрешенных возможностей, предоставляемых исполняемым файлом.См. Возможности (7).

  • ETXTBSY Указанный исполняемый файл был открыт для записи одним или несколькими процессами.

...