繁体   English   中英

它应该在c中的exec函数不返回-1

[英]Exec function in c is not returning -1 when it should

我使用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。

execv成功地完成了它的工作。 进程./code.x执行,然后因断言而退出。

exec系列函数不关心进程的返回值。 一旦进程启动,调用进程就会被有效终止并消失。

如果出于某种原因无法启动进程,Exec将仅返回 具体来说,只有这些错误(取自手册页)才会导致exec返回并将errno为以下值之一:

  • E2BIG的总字节数(envp)和参数列表(argv)太大。

  • EACCES对文件名的路径前缀的组件或脚本解释器的名称拒绝搜索权限。 (另见path_resolution(7)。)

  • EACCES文件或脚本解释器不是常规文件。

  • EACCES对文件或脚本或ELF解释器的执行权限被拒绝。

  • EACCES文件系统已安装noexec。

  • EAGAIN (自Linux 3.1起)使用set * uid()调用之一改变了它的真实UID后,调用者是 - 并且现在仍高于其RLIMIT_NPROC资源限制(参见setrlimit(2))。 有关此错误的更详细说明,请参阅NOTES。

  • EFAULT文件名或向量argv或envp中的指针之一指向可访问的地址空间之外。

  • EINVAL ELF可执行文件具有多个PT_INTERP段(即,尝试命名多个解释器)。

  • EIO发生I / O错误。

  • 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或set-group-ID位设置。

  • EPERM正在跟踪进程,用户不是超级用户,文件具有set-user-ID或set-group-ID位设置。

  • EPERM “功能愚蠢”的应用程序无法获得可执行文件授予的全套允许功能。 见功能(7)。

  • ETXTBSY指定的可执行文件由一个或多个进程打开以供写入。

exec系列函数从可执行文件加载的初始状态的新程序替换调用进程 它们只能在此替换失败时失败,例如由于请求的文件不存在或者调用用户没有访问/执行它的权限。

如果你正在调用的程序./code.x的断言失败,那么这./code.x超过了execv可能失败的程度; 此时,执行execv的原始程序状态不再存在,因为它已被替换。 父进程将通过wait -family函数看到它退出,并且可以检查wait -family函数报告的状态以确定它退出的原因。

如果程序开始运行, exec*函数会成功。 你的程序确实开始运行了。

断言失败导致程序中止 ,退出信号 Linux 手册页wait (2)解释了:

WEXITSTATUS(wstatus)

返回子项的退出状态。 这包括子项在exit(3)_exit(2)的调用中指定的status参数的最低有效8位,或者作为main() return语句的参数。 仅当WIFEXITED返回true时才应使用此宏。

如果您没有检查WIFEXITED(status)是否为true,那么WEXITSTATUS(status)就是垃圾

相反,检查WIFSIGNALED(status) ,如果为true,则获取信号 - WTERMSIG(status) ,该值应等于SIGABRT

Exec函数系列用新的过程映像替换现有的过程映像。 这就是为什么在生成另一个进程之前需要fork,因为当前正在运行的进程被完全替换,这包括程序计数器,它跟踪下一条要执行的指令。

printf("should fail");

因为你调用execv(args[0], args)的瞬间,程序计数器被移动到执行args [0],从而留下了导致该print语句的执行路径,因此永远不会被激活。

Exec在替换图像时遇到错误的情况下返回-1,并且与正在执行的程序的返回值完全无关。 这是因为调用Exec之后的两个进程根本没有相互协调。 请记住: fork()命令创建了一个新的地址空间,这意味着这些进程现在在单独的可执行文件的不同域中运行。

一些文档可能有所帮助:

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

希望这有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM