Having issues with execvp() - c++

So here is the bit of my code that's giving me problems:
void childProcessHandler(string command){
int argCounter = 0;
for(int i=0; i!=command.size(); i++)
argCounter+=( command.at(i) == ' ');
char * temp, *token;
char *childArgs[argCounter];
argCounter = 1;
temp = new char [command.size()+1];
strcpy (temp, command.c_str());
token = strtok (temp," ");
childArgs[0] = token;
while (token!=NULL)
{
token = strtok(NULL," ");
childArgs[argCounter] = token;
argCounter++;
}
//delete[] temp; //Should remove token as well?
execvp(childArgs[0], childArgs);
cout<<"PROBLEM!"<<endl;
exit(-1);
}
In the main() method my code gets to a point where it forks() (the parent process then waits for the child to exit.) then the child process (process ID == 0 yes?) calls the method childProcessHandler with the user input (command to run + args) as it's argument. Then I tokenize the user input and call execvp on it.
Everything compiles and executes. The line after execvp is never reached because execvp only returns when there is an error yes?
The project is to simulate a unix terminal however when I give it the command "date" nothing gets printed like it should... The child exits and the parent process resumes just fine however nothing is sent back up to the terminal window...
What am I doing wrong?
(Also we were "recommended" to use strtok to tokenize it but if anyone has anything simpler i'm open to opinions.)
THANKS!
EDIT
The above code works, for example, if I type in "date " instead of "date". I think there might be something fishy with the "tokenizer" not putting a null character at the end of the childArgs[] array. I'll play around with that and thanks for the quick responses!
(Ninja edit, also commented out delete[] temp for the time being)

You're mixing std::string and char/char*. Fine, but you have to be careful, they have different behaviours.
In particular this line:
temp = new char [command.size()+1];
Is creating an actual array to hold a string in.
token = strtok (temp," ");
This is making token (which is just a pointer) point to a place inside temp. strtok() modifies the input string to make a temporary string within a string (sounds crazy, I know).
You need to copy the string strtok() gives you into a permanent home. Either use std::string to save you time and code, or do it the char* way and allocate the new string yourself. E.g. instead of:
childArgs[0] = token;
you need:
childArgs[0] = new char[strlen(token)+1];
strcpy(childArgs[0], token);
The same applies to tokens stored in the array during the loop over the command arguments.

Your childargs vector of pointers point into the bytes allocated in the block of memory "temp". When you free temp, you are removing the memory pointed to by the childargs pointers, possibly corrupting some of the values within your vector.
Remove the call to delete[] to stop freeing the memory pointed to by the childargs pointers. You will not be leaking memory. Once you call exec_() your entire process image is replaced anyway. The only thing that survives a call to exec_() (for the most part) are your file descriptors.
As a test, try something a bit more simple: After your call to fork() in the child, just call exec with the path to "date". Make that work before fiddling with the parameter list vector.
As another test, remove your call to exec, and print out your entire vector of pointers to make sure that your tokenizing is working the way you think it should. Remember that your final entry must be NULL so that you know where the end of the vector is.

Related

How to pull text out of a .txt and store it into a dynamic 2d array?

I need to pull text line by line out of my .txt file and store it into a dynamic array that has new space allocated every time I pull a new line out of the .txt file. My code seems to pull out the first line just fine and store it into the first pointers array, but on the second loop, it seems to reset all the pointers arrays which gives me memory allocation errors when I later try to access it. Why does this happen especially when I don't touch the pointers and their arrays after I store stuff into them?
char** temp = nullptr;
char buffer[256];
int index = 0;
// Open File
fstream myFile;
myFile.open("pantry.txt", ios::in);
if (myFile.is_open())
{
while (!myFile.eof())
{
myFile >> buffer; // Pull line out of txt.file
temp = new char* [index + 1]; // Create new pointer
temp[index] = new char[strlen(buffer)+1]; // Create char array pointed at by new pointer
#pragma warning(suppress : 4996) // Turns off complier warning
strcpy(temp[index], buffer); //Copy buffer into new char array
index++; // Increment our index counter int
}
for (int i = 0; i < index; i++)
{
cout << temp[i] << endl;
}
If allocated and stored correctly I want it to just print out the txt file exactly.
Instead, I get
Exception thrown at 0x7B9A08CC (ucrtbased.dll) in PE 12.4.exe: 0xC0000005: Access violation reading location 0xCDCDCDCD.
pantry.txt
Basil
Flat Leaf Parsely
Thyme
Sage
Cumin
Steak Seasoning
Mace
Garlic Powder
There are multiple bugs in the shown code.
while (!myFile.eof())
This is always a bug that also must be fixed, in addition to the main problem with the shown code:
temp = new char* [index + 1];
To help you understand the problem with this line, it's helpful to remember The Golden Rule Of Computer Programming:
Your computer always does exactly what you tell it to do instead of
what you want it to do.
According to the Golden Rule, the above line tells your computer, exactly: "new something, and assign it to temp".
And this is what your computer will do every time it executes this line. This line is executed once, on each iteration of this loop. The next time this loop runs, the previously newed temp will be replaced by another one, leaking everything that it pointed to before. Why should your computer do anything else, on this line? After all, this is exactly what you told your computer to do. And this is why you observed that this will "reset all the pointers arrays" on every iteration of the loop, resulting in "memory allocation errors".
In any case, this entire chunk of logic needs to be scrapped and rewritten from scratch, this time using the right logic. The simplest thing to do is to actually use the C++ library's std::vector and std::string objects, which will do all the memory allocation for you, correctly. Modern C++ code rarely needs to new anything, and will use C++ library's containers, instead.
It is possible that the goal of your assignment is to demonstrate proper use of low-level memory allocation and deallocation logic. In this case you will need to find some other way of doing this. Since you don't know the number of lines in advance, one approach will be to build a linked list, one line at a time, as each line gets read from the file. The final array, with all the character pointers gets allocated only after the entire file is read (and the number of lines is known), the pointers moved to the array, and the temporary linked list deleted. Or, perhaps implement a std::vector-like algorithm that progressively allocates a new pointer array, when it is full, copies over all the character pointers to a bigger array and then deletes the original one.
Of course, that's a lot of work. But unless the purpose of your assignment or task is to correctly implement low-level memory allocations and deallocation, why go through all the work and pain to do what std::vector and std::string already do, when you can simply use them, in just five or six lines of code, that will replace all of the above?

Random behavior of an array of char arrays

I have an array of character arrays that is split based on a pipe ('|') operator (example below) and the function I am using to create this array seems to work on occasion, and then on occasion, it will create the array then abort and give me one of two different errors.
I am not sure what I am doing wrong? Particularly I am not sure why it creates successfully every time but then seems to break after creation about half the time, regardless of the input.
Example array:
"here is | an example | input" = {"here is", "an example", "input"}
Errors:
Error in './msh': malloc(): memory corruption (fast): 0x000...
Error in './msh': free(): invalid pointer: 0x0000....
Code:
char** allArgs = new char*[100];
void createArgArrays(const char* line) {
char* token;
token = strtok((char*)line, "|");
int i = 0;
while(token != NULL) {
allArgs[i] = token;
i++;
token = strtok(NULL, "|");
}
}
Where I call the code:
string input;
getline(cin, input);
createArgArrays(input.c_str());
Any insight/help is greatly appreciated.
c_str() returns a const char *. strtok() modifies the string it refers to.
Per http://www.cplusplus.com/reference/string/string/c_str/:
c++98
A program shall not alter any of the characters in this sequence.
Don't cast away const to force things to "work".
A few things:
The C++ way is sometimes different than the C way.
Andrew Henle's point about casting should be carved into stone tablets.
If you really want to use a C function, try walking the string using strchr().
Also, try something like std::vector<std::string> (see std::vector::push_back) to store your string chunks - it'll be a bit cleaner and avoids an arbitrary cap on the size of allArgs.
Another thing you could look at is boost::split(), which probably does exactly what you want anyway.

How to clear the buffer in a (char*)?

In my program I have a char* buffer which is being used inside a thread sequence which carries text from one function into another, but the text is different through the run-time in my program. The question that I am asking is, which function can I use to clear the previously used text out of the char* ?
For example, I have the following code:
int GameUtils::GetText(char *text)
{
for(int i=0; i<LINES_OF_TEXT; i++)
{
if(line[i][0]!=0)
{
strcpy(text, line[i]);
MessageBox(0, text, 0, 0);
line[i][0]=0;
return 1;
}
}
return 0;
}
line is defined as such: char GameUtils::line[2][32];
When the messagebox is output on the screen (while code is executed). I get some random junk characters in the text field. Can anyone tell me why this is?
Also! Note that line is assigned as stated in my previous question.
The function which assigns line is:
for (int x=0; x<((int)(strlen(szLine)+1)); x++)
{
if (szLine[x]==' ' || szLine[x]=='\0')
{
m=x;
for (y=0, z=n; z<m; y++, z++)
{
line[w][y]=szLine[z];
}
n=x+1;
w++;
}
}
The above function simply takes a parameter szLine[512] which is passed from my game interface and splits up the line assorting each space as a new parameter.
As an example, if inside the game the user states the line:
/msg <player> <message>
The function would assign each separate word to the line variable, respectively.
Such that, after the function is finished. line would look like
line[0] = /msg
line[1] = <player>
line[2] = <message>
So my question overall is as follows. Am I taking the cleaniest/most appropriate approach at this problem? If not, can anyone show me a better way to approach this problem? Also, can anyone explain to me why I am getting junk characters in the text parameter when the messagebox executes?
EDIT
After viewing the preview of my submitted question; I noticed I have defined char GameUtils::line[2][32] as a 2-dimensional array. I had done this earlier to test. I now understand this could have been the cause to my problem. Can anyone suggest me a replacement for this if I don't know the exact amount of parameters that could be inputted into this variable. The user can issue different requests each time like "/help ", "/msg ", "/whois ", "/create "...
When memory is allocated it isn't zeroed first (at least when using malloc, calloc - however, does zero memory first).
To clear a buffer in C (rather than C++), you have a few options:
Allocate the buffer using calloc instead of malloc.
Use Win32's ZeroMemory function
Use memset, like so: memset( buffer, 0x00, BUFFER_SIZE );
However you're clearly using C++, so you should use the standard library and C++ idioms rather than C-style things, that means using std::string instead of char*, and if you have to use buffers directly then the C++ way of zeroing (or filling) an array or buffer is std::fill.
First off, I would avoid using double dimensional arrays if you can avoid it. Maybe look into std::string:
http://www.cplusplus.com/reference/string/string/
As for why a char array might have "random junk" in it, when you allocate a buffer in C++, it always has data in it. You have to manually set the data to 0 if you want it to be empty. So when you first allocate an array, it might be a idea to zero out all the values first.

Segmentation Fault on Assigning string Array

I have been trying to return an array of strings for a function for a couple of days to no avail. While I was searching around StackOverflow, I found that it would be a better idea to have a parameter that will be assigned the value of an array. So, here is my code example (not the actual usage, but a mockup of how I am trying to use the function). I am sorry if the code is a bit sloppy. I have been testing things out with it for a while.
void splitOn(string message, string delim, string***toCh) {
string** rString = new string*;
string lArr[numberOf(message, delim)+1];
for(int index=0; index<numberOf(message, delim)+2; index++) {
lArr[index]=message.substr(0, message.find(delim)).c_str();
message = message.substr(message.find(delim)+1, message.length());
rString[index]=&lArr[index];
cout << "IN LOOP "<<*rString[index]<<endl;
}
rString[numberOf(message, string(delim))] = &message;
toCh=&rString;
}
int main(){
string***arr;
splitOn("fox.over.lazy.dog", ".", arr);
cout << **arr[0]<<endl;
Note:
numberOf() takes a string and a delimiter(string) and returns how many times the delimiter is found within the string.
strings are from std::string
lArr (the local array within the loop) and *rString all give correct output.
Although I am trying to assign the array to a parameter, learning how to return an array is more appealing to me.
I could hack this together with a file and getLine(), but I would prefer to learn how to properly do this.
You're trying to return local variables, which will never work. You and your caller need to agree on how to allocate the return value. In C++ as the commenters mention this would normally be done by passing a reference to a vector to handle your allocation for you.
In C you have two options, you can either get the caller to pass in a big enough allocation, or use multiple calls to malloc in the callee (not forgetting the calls to free in the caller!)
For instance, if you pass a writable character array, you can simply overwrite the separator characters with null characters to split it up into individual strings without having to allocate new copies.

Splitting a std::string into two const char*s resulting in the second const char* overwriting the first

I am taking a line of input which is separated by a space and trying to read the data into two integer variables.
for instance: "0 1" should give child1 == 0, child2 == 1.
The code I'm using is as follows:
int separator = input.find(' ');
const char* child1_str = input.substr(0, separator).c_str(); // Everything is as expected here.
const char* child2_str = input.substr(
separator+1, //Start with the next char after the separator
input.length()-(separator+1) // And work to the end of the input string.
).c_str(); // But now child1_str is showing the same location in memory as child2_str!
int child1 = atoi(child1_str);
int child2 = atoi(child2_str); // and thus are both of these getting assigned the integer '1'.
// do work
What's happening is perplexing me to no end. I'm monitoring the sequence with the Eclipse debugger (gdb). When the function starts, child1_str and child2_str are shown to have different memory locations (as they should). After splitting the string at separator and getting the first value, child1_str holds '0' as expected.
However, the next line, which assigns a value to child2_str not only assigns the correct value to child2_str, but also overwrites child1_str. I don't even mean the character value is overwritten, I mean that the debugger shows child1_str and child2_str to share the same location in memory.
What the what?
1) Yes, I'll be happy to listen to other suggestions to convert a string to an int -- this was how I learned to do it a long time ago, and I've never had a problem with it, so never needed to change, however:
2) Even if there's a better way to perform the conversion, I would still like to know what's going on here! This is my ultimate question. So even if you come up with a better algorithm, the selected answer will be the one that helps me understand why my algorithm fails.
3) Yes, I know that std::string is C++ and const char* is standard C. atoi requires a c string. I'm tagging this as C++ because the input will absolutely be coming as a std::string from the framework I am using.
First, the superior solutions.
In C++11 you can use the newfangled std::stoi function:
int child1 = std::stoi(input.substr(0, separator));
Failing that, you can use boost::lexical_cast:
int child1 = boost::lexical_cast<int>(input.substr(0, separator));
Now, an explanation.
input.substr(0, separator) creates a temporary std::string object that dies at the semicolon. Calling c_str() on that temporary object gives you a pointer that is only valid as long as the temporary lives. This means that, on the next line, the pointer is already invalid. Dereferencing that pointer has undefined behaviour. Then weird things happens, as is often the case with undefined behaviour.
The value returned by c_str() is invalid after the string is destructed. So when you run this line:
const char* child1_str = input.substr(0, separator).c_str();
The substr function returns a temporary string. After the line is run, this temporary string is destructed and the child1_str pointer becomes invalid. Accessing that pointer results in undefined behavior.
What you should do is assign the result of substr to a local std::string variable. Then you can call c_str() on that variable, and the result will be valid until the variable is destructed (at the end of the block).
Others have already pointed out the problem with your current code. Here's how I'd do the conversion:
std::istringstream buffer(input);
buffer >> child1 >> child2;
Much simpler and more straightforward, not to mention considerably more flexible (e.g., it'll continue to work even if the input has a tab or two spaces between the numbers).
input.substr returns a temporary std::string. Since you are not saving it anywhere, it gets destroyed. Anything that happens afterwards depends solely on your luck.
I recommend using an istringstream.