Reputation:
I am using an execv function to run a program called code.x. code.x has a part where it guarantees its failure by Assertion. My code that runs execl is:
#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;
}
the code prints
Success
code.x: code.c:15: main: Assertion '0 == 1' failed.
Success
done
"should fail" is never printed and WEXITSTATUS(status) shows that the exit status is 0.
Upvotes: 4
Views: 1317
Reputation: 793
execv
successfully did its job. The process ./code.x
executed, then exited because of an assertiong.
The exec family of functions don't care about the process's return value. Once the process starts, the calling process is effectively terminated and gone.
Exec will only return if for some reason the process couldn't be started at all. Specifically, only these errors (taken from the man page) will cause exec to return and set errno
to one of these values:
E2BIG
The total number of bytes in the environment (envp) and argument list (argv) is too large.
EACCES
Search permission is denied on a component of the path prefix of filename or the name of a script interpreter. (See also path_resolution(7).)
EACCES
The file or a script interpreter is not a regular file.
EACCES
Execute permission is denied for the file or a script or ELF interpreter.
EACCES
The filesystem is mounted noexec.
EAGAIN
(since Linux 3.1)
Having changed its real UID using one of the set*uid() calls, the caller was—and is now still—above its RLIMIT_NPROC resource limit (see
setrlimit(2)). For a more detailed explanation of this error, see NOTES.
EFAULT
filename or one of the pointers in the vectors argv or envp points outside your accessible address space.
EINVAL
An ELF executable had more than one PT_INTERP segment (i.e., tried to name more than one interpreter).
EIO
An I/O error occurred.
EISDIR
An ELF interpreter was a directory.
ELIBBAD
An ELF interpreter was not in a recognized format.
ELOOP
Too many symbolic links were encountered in resolving filename or the name of a script or ELF interpreter.
ELOOP
The maximum recursion limit was reached during recursive script interpretation (see "Interpreter scripts", above). Before Linux 3.8, the
error produced for this case was ENOEXEC.
EMFILE
The per-process limit on the number of open file descriptors has been reached.
ENAMETOOLONG
filename is too long.
ENFILE
The system-wide limit on the total number of open files has been reached.
ENOENT
The file filename or a script or ELF interpreter does not exist, or a shared library needed for the file or interpreter cannot be found.
ENOEXEC
An executable is not in a recognized format, is for the wrong architecture, or has some other format error that means it cannot be executed.
ENOMEM
Insufficient kernel memory was available.
ENOTDIR
A component of the path prefix of filename or a script or ELF interpreter is not a directory.
EPERM
The filesystem is mounted nosuid, the user is not the superuser, and the file has the set-user-ID or set-group-ID bit set.
EPERM
The process is being traced, the user is not the superuser and the file has the set-user-ID or set-group-ID bit set.
EPERM
A "capability-dumb" applications would not obtain the full set of permitted capabilities granted by the executable file. See capabilities(7).
ETXTBSY
The specified executable was open for writing by one or more processes.
Upvotes: 1
Reputation: 748
The Exec function family replaces the existing process image with a new process image. This is why it is required to fork before spawning another process, because the currently running process is completely replaced, this includes the program counter, which keeps track of the next instruction to execute.
printf("should fail");
is never excecuted because the instant you called execv(args[0], args)
, the program counter was moved to execute args[0], thus leaving behind the execution path that would have resulted in that print statement.
Exec returns -1 on the condition that it encountered an error while replacing the image, and has absolutely no relation to the return value of the program being executed. This is because the two processes, after Exec is called, are not coordinating with each other at all. Remember: the fork()
command created a new address space, which means that these processes are now running in separate domains on separate executables.
Some documentation may be of help:
http://man7.org/linux/man-pages/man3/exec.3.html
Hope this helped.
Upvotes: 0
Reputation: 133879
exec*
functions succeed if the program starts running. Your program did start running.
An assertion failure causes the program to abort, exit with a signal. The Linux manual page wait
(2) explains that:
WEXITSTATUS(wstatus)
returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the child specified in a call to
exit(3)
or_exit(2)
or as the argument for a return statement inmain()
. This macro should be employed only ifWIFEXITED
returned true.
If you didn't check that WIFEXITED(status)
is true, then WEXITSTATUS(status)
is garbage.
Instead, check WIFSIGNALED(status)
and if true, get the signal - WTERMSIG(status)
, which should equal to SIGABRT
.
Upvotes: 1
Reputation: 215193
The exec
family of functions replace the calling process with a new program in its initial state loaded from an executable file. They can only fail if this replacement fails, e.g. due to the requested file not existing or the invoking user not having permissions to access/execute it.
If an assertion failure in the program ./code.x
you're invoking happens, this is long past the point where execv
could have failed; at this point, the original program state where execv
was performed no longer exists, because it was already replaced. The parent process will see it exit via a wait
-family function, and can inspect the status reported by the wait
-family function to determine why it exited.
Upvotes: 1