[英]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.