Reputation: 472
I have a program that runs indefinitely. For testing purposes I have made a wrapper program that kills the other after a specified amount of time (specified via command line/terminal args). The program being forked requires that it is passed two folders with the same name (I have no control over this), so I simply pass it the same arg twice as can be seen here:
pid_t pid = fork();
if(pid == 0)
{
//build the execution string
char* test[2];
test[0] = argv[2];
test[1] = argv[2];
test[2] = NULL;
cout << "test[0] is " << test[0] << endl;
cout << "test[1] is " << test[1] << endl;
cout << "argv[1] is " << argv[1] << endl;
execvp(argv[1],test);
}
The problem is that the program being passed in argv[1] keeps segmentation faulting. If I call the by itself via the terminal it runs with no problems. I am passing the same folder in both cases. Can anyone tell me why it isn't working for execvp?
I should mention a co-worker ran it on his computer as well, and it will stand up fine the first time, but each time after that, it will seg fault.
edit: I have added a null term to test, however, this has not fixed the issue.
The command's form is exactly:
<executable> <wrapped prog> <folder> <duration>
In relative paths it's:
Intel/debug/Tester.exe <program> test 10
Upvotes: 1
Views: 512
Reputation: 754920
Given the specification:
The command's form is exactly:
<executable> <wrapped prog> <folder> <duration>
In relative paths it's:
Intel/debug/Tester.exe <program> test 10
and also:
The program being forked requires that it is passed two folders with the same name…
then, assuming you've checked that the wrapper is passed 4 arguments, the code you need is:
pid_t pid = fork();
if (pid == 0)
{
//build the execution string
char *test[4]; // Note the size!
test[0] = argv[1]; // Program name: argv[0] in exec'd process
test[1] = argv[2]; // Directory name: argv[1] …
test[2] = argv[2]; // Directory name: argv[2] …
test[3] = NULL; // Null terminator
cout << "test[0] is " << test[0] << endl;
cout << "test[1] is " << test[1] << endl;
cout << "test[2] is " << test[2] << endl;
execvp(test[0], test);
cerr << "Failed to exec '" << test[0] << "': " << strerror(errno) << endl;
exit(1); // Or throw an exception, or …
}
There is seldom (but not never) a reason to invoke execvp()
other than using the idiom execvp(argv[0], argv)
for the array of arguments in argv
.
Note that this code ensures that the control flow doesn't escape from the statement block that is supposed to represent the child. Having the child process continue afterwards, usually in effect thinking it is a parent process, leads to confusion. Always make sure the child execs or exits. (That's a rhetorical over-statement — yes; but there's a large chunk of truth behind the idea too.) Also, since this is C++, you may need to consider How to end C++ code?. That complicates life. The crucial thing is that if the child process fails to exec, it does not continue as if it was a parent process.
Upvotes: 1
Reputation: 60145
If the length of the array is static, you might be better off with
execlp
execlp(argv[1], argv[1], argv[2], argv[2], (char*)0);
As for execvp
, the array should start with the name of the executable and end with NULL
.
execvp
char* args[] = { argv[1], argv[2], argv[2], NULL };
execvp(argv[1], args);
In any case, if all you want is a simple wrapper that runs a single child with a timeout, then your program could be very simple and general if only you'd be willing to start with the timeout argument:
/*runWithTimeout.c
compile with: make runWithTimeout
run with: ./runWithTimeout seconds program arguments...
*/
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
int main(int argc, char** argv)
{
assert(argc >= 1+2);
int pid, status = 1;
if((pid = fork()) == 0) {
alarm(atoi(argv[1]));
execvp(argv[2], argv + 2);
/*^the child ends here if execvp succeeds,
otherwise fall-through and return the default error status of 1
(once in child (which has no one to wait on) and
then in the parent (which gets the status from the child))*/
perror("Couldn't exec");
}else if(pid < 0){ perror("Couldn't fork"); };
wait(&status);
return status;
}
Upvotes: 2
Reputation: 182865
You want:
char* test[3];
test[0] = argv[2];
test[1] = argv[2];
test[2] = NULL;
You need a NULL parameter to mark the end of the parameter list.
Upvotes: 1
Reputation: 443
You can turn on core dumps ( make sure to shut them off when done ) ulimit -c unlimited
. Run it before you run your main process. ( I would be leary of running it in the fork though you probably can. )
When your program crashes this will produce a core dump which you can examine with gdb.
For help with core files, you can just google them.
Other then that. You can make a script which launches your file. You can use the script to log stuff.
Upvotes: 1
Reputation: 330
Array passed as arguments should be null-terminated. For example:
char *test[3]={0};
...
Upvotes: 2