Reputation: 1
I am building a simple command line interpreter. It reads user input from stdin and parses it to run programs in seperate child processes.
User input will be in the format: ... with arg1 to arg4 being possible command line arguments.
(I am constraining the input format, path is <100 chars long, each cmd line argument is <20 chars long, there are up to 4 cmd line arguments)
For now the main() function only reads in one line of user input.
My problem is, I abstracted the input parsing and storing into a function called extractArgs(char**,char*). This function parses the input and extracts the data needed for the execv(char* argc, char* argv[]) arguments.
It definitely parses the input correctly. I put debugging print statements in main and extractArgs to print out the strings in the argv array. The one in extractArgs shows that argv holds the correct values, but the one in main prints nonsense.
I suspect it has something to do with memory being recycled after extractArgs finishes execution, so the argv pointers end up pointing at nonsense when the old values are overwritten..
Is this correct? What can I do to stop that? Must I use malloc? Is there no way to simply keep the pointers in the argv array from being recycled?
// argv is the char* array to store cmd args from stdin for execv,
// path is string to store path from user input
int extractArgs(char** argv, char* path)
{
const char* fmessageNotFound = "%s not found\n";
struct stat buf;
const char delim[2] = " ";
char argStr[90];
char* token;
int i;
scanf("%s", path); // get path
// handle invalid program path
if (stat(path, &buf) == -1)
{
printf(fmessageNotFound, path);
return -1;
}
argv[0] = path; // argv[0] must be program name
argv[1] = NULL; // set terminating element for 0 argument case.
// read all cmd line args.
// constraints: up to 4 args, arg lengths <20 chars
fgets(argStr, 90, stdin);
argStr[strcspn(argStr, "\n")] = '\0'; // clear trailing \n
// populate argv array
token = strtok(argStr, " ");
for (i = 1; i < 5 && token != NULL; i++)
{
argv[i] = token;
token = strtok(NULL, " ");
}
// set terminating element after populating argv
argv[i] = NULL;
// test and print all the arguments
i = 0;
while (argv[i] != NULL) {
// EVERYTHING WORKS HERE
printf("%s\n", argv[i]);
i++;
}
return 0;
}
int main()
{
pid_t chpid;
char* argv[6]; // max 4 cmd args + name + NULL terminator
char path[100]; // command path length <100
if (extractArgs(argv, path) == -1) // invalid path
{
fgets(path, 100, stdin); // clean up newline
return;
}
// Print values in argv
int i = 0;
while (argv[i] != NULL) {
// PRINTS NONSENSE.
printf("%s\n", argv[i]);
i++;
}
chpid = fork();
if (chpid == 0)
{
execv(path, argv);
}
wait(NULL);
return 0;
}
Upvotes: 0
Views: 676
Reputation: 409166
In the extractArgs
function, you store pointers to the local array argStr
in your argv
array.
Once the function returns those pointers are no longer valid as argStr
has gone out of scope. This leads to undefined behavior when you try to use the stray pointers in the argv
array.
Upvotes: 1