Why does the following code produce a segmentation fault? - c++

I'm trying to execute a UNIX command via my program that will handle up to 4 arguments, why does this either produce a seg fault or other errors?
using namespace std;
int main() {
char buffer[255];
cin >> buffer;
char* firstPtr;
char* secondPtr;
char* thirdPtr;
char* fourthPtr;
firstPtr = strtok(buffer, " ");
secondPtr = strtok(NULL, " ");
thirdPtr = strtok(NULL, " ");
fourthPtr = strtok(NULL, " ");
execlp(firstPtr, secondPtr);
return 0;
}

The crash is because your buffer overflows.
Try to use std::cin.getline(buffer, sizeof(buffer)) instead of std::cin >> buffer
Also note that strtok may return NULL, so be sure you handle it.

I think you should use
char buffer[255];
cin.getline(buffer, 255);
Otherwise your second, third and fourth pointer will be empty.

If you check the man page of execlp, you will notice that the first argument (the second parameter to the method, the arg0 parameter) is mandatory, in addition to any other parameters you might pass to the function via variadic parameters - and it is also mentioned in the text that
The list of arguments must be terminated by a NULL pointer.
The first argument (secondPtr in your case) should be the name of the executable; so you're violating the convention by passing in NULL here (because of the cin >> others have pointed out already).
But in addition, you're also missing at least one more argument at the end which needs to be NULL.
So, a study of man pages is highly recommended!

Related

Using strtok_s more than once

I am using strtok_s to pull out a value from a C-String based on user input. However, I need to be able to call this function more than one time. Currently when I do it has a problem going through strtok_s. I believe because it is still pointing to a different location and not starting again. ListOfCoeffs is my c-string, which is just a c-string list that has doubles. Degree is the int value that is passed into the function from the user. Is there any way to "reset" strtok so that it will allow me to use this function more than one time without shutting the program down? Apologies for poor style using strtok_s, I am not familiar with it at all.
char * pch;
double coeffValue;
char * context;
pch = strtok_s(listOfCoeffs, " ", &context);
if (degree == 0)
{
// DO NOTHING
}
else
{
for (int i = 0; i < degree; i++)
{
pch = strtok_s(NULL, " ", &context);
}
}
coeffValue = atof(pch);
return coeffValue;
The strtok family of functions destructively modify the input string while tokenizing it. If you want to potentially start over at the beginning, you need to copy the string before passing it to strtok.

Function call resets passed global structs' fields

With reference to the code below: After calling the function CheckSMS and passing the struct * DB1, the fields are updated according the the strtok call. This function reads and parses a text message, storing its contents into char* fields of the DB struct.
In the main loop, I have called Serial.println(DB1.last_order) before and after calling the CheckSMS function. If I have received a text, the order is printed appropriately in the main loop, however on the next call to CheckSMS, DB1.last_order is cleared, replaced with a \n or a NULL or something. I cannot figure out why DB1.last_order does not retain its value, and rather, it is overwritten with every call to CheckSMS. Thanks for any help.
Note - All text messages contain "CMT+", therefore writing to DB1 only happens when a text is received. Calling CheckSMS when no text is received should simply skip through.
int CheckSMS(Robot *DB1) {
int j = 0;
char response[100];
char *pch;
unsigned long previous;
memset(response, '\0', 100);
while(Serial2.available()>0){
response[j] = Serial2.read();
j++;
Serial.println("inc");
}
delay(100);
if (strstr(response, "CMT:") != NULL){
DB1->new_message = strtok(response, " ,");
DB1->last_phone = strtok(NULL, " ,");
pch = strtok(NULL, " ,");
DB1->last_date = strtok(NULL, " ,");
DB1->last_time = strtok(NULL, " ,\n");
DB1->last_order = strtok(NULL," ,\n");
new_message = 1;
}
else{
}
return 0;
}
The strtok function returns pointers to the string you're tokenizing, the local array response in your case. When the function returns the response array goes out of scope and disappears, leaving your structure with pointers to a string that no longer exists, and giving you undefined behavior.
You have a couple of solutions:
Allocate the string dynamically using malloc, but then you must save it in the structure so you can free it when you're done with the structure
Make the response array static, but then the next call to the function will have the same array leading the old data to be updated
Pass in a string to store the response and use that string, the string must have a lifetime at least as long as the structure and don't change contents. The string can of course be a member of the structure itself
The answer Joachim gave is correct, I just want to add that you could also change the Robot structure to contain char arrays (like this: char new_message[MAX_BUF_CHARS]; and so on). Be sure to have enough space in them. Then instead of assigning the pointers returned from strtok, copy the strings in there.

How to check the contents of a LPTSTR string?

I'm trying to understand why a segmentation fault (SIGSEGV) occurs during the execution of this piece of code. This error occurs when testing the condition specified in the while instruction, but it does not occur at the first iteration, but at the second iteration.
LPTSTR arrayStr[STR_COUNT];
LPTSTR inputStr;
LPTSTR str;
// calls a function from external library
// in order to set the inputStr string
set_input_str(param1, (char*)&inputStr, param3);
str = inputStr;
while( *str != '\0' )
{
if( debug )
printf("String[%d]: %s\n", i, (char*)str);
arrayStr[i] = str;
str = str + strlen((char*)str) + 1;
i++;
}
After reading this answer, I have done some research on the internet and found this article, so I tried to modify the above code, using this piece of code read in this article (see below). However, this change did not solve the problem.
for (LPTSTR pszz = pszzStart; *pszz; pszz += lstrlen(pszz) + 1) {
... do something with pszz ...
}
As assumed in this answer, it seems that the code expects double null terminated arrays of string. Therefore, I wonder how I could check the contents of the inputStr string, in order to check if it actually contains only one null terminator char.
NOTE: the number of characters in the string printed from printf instruction is twice the value returned by the lstrlen(str) function call at the first iteration.
OK, now that you've included the rest of the code it is clear that it is indeed meant to parse a set of consecutive strings. The problem is that you're mixing narrow and wide string types. All you need to do to fix it is change the variable definitions (and remove the casts):
char *arrayStr[STR_COUNT];
char *inputStr;
char *str;
// calls a function from external library
// in order to set the inputStr string
set_input_str(param1, &inputStr, param3);
str = inputStr;
while( *str != '\0' )
{
if( debug )
printf("String[%d]: %s\n", i, str);
arrayStr[i] = str;
str = str + strlen(str) + 1;
i++;
}
Specifically, the issue was occurring on this line:
while( *str != '\0' )
since you hadn't cast str to char * the comparison was looking for a wide nul rather than a narrow nul.
str = str + strlen(str) + 1;
You go out of bounds, change to
str = str + 1;
or simply:
str++;
Of course you are inconsistently using TSTR and strlen, the latter assuming TCHAR = char
In any case, strlen returns the length of the string, which is the number of characters it contains not including the nul character.
Your arithmetic is out by one but you know you have to add one to the length of the string when you allocate the buffer.
Here however you are starting at position 0 and adding the length which means you are at position len which is the length of the string. Now the string runs from offset 0 to offset len - 1 and offset len holds the null character. Offset len + 1 is out of bounds.
Sometimes you might get away with reading it, if there is extra padding, but it is undefined behaviour and here you got a segfault.
This looks to me like code that expects double null terminated arrays of strings. I suspect that you are passing a single null terminated string.
So you are using something like this:
const char* inputStr = "blah";
but the code expects two null terminators. Such as:
const char* inputStr = "blah\0";
or perhaps an input value with multiple strings:
const char* inputStr = "foo\0bar\0";
Note that these final two strings are indeed double null terminated. Although only one null terminator is written explicitly at the end of the string, the compiler adds another one implicitly.
Your question edit throws a new spanner in the works? The cast in
strlen((char*)str)
is massively dubious. If you need to cast then the cast must be wrong. One wonders what LPTSTR expands to for you. Presumably it expands to wchar_t* since you added that cast to make the code compile. And if so, then the cast does no good. You are lying to the compiler (str is not char*) and lying to the compiler never ends well.
The reason for the segmentation fault is already given by Alter's answer. However, I'd like to add that the usual style of parsing a C-style string is more elegant and less verbose
while (char ch = *str++)
{
// other instructions
// ...
}
The scope of ch is only within in the body of the loop.
Aside: Either tag the question as C or C++ but not both, they're different languages.

Strange behavior with function strncpy?

In my project,I have met these strange problem with strncpy. I have checked the reference. But the function strncpy behavior make me confused.
In this function, when it runs to strncpy(subs,target,term_len);
While I don't know why there is two blanks after the string?!!! It is a big project, I cannot paste all the code here. Following is just a piece. All my code is here.
char* subs = new char[len];
while(top<=bottom){
char* term = m_strTermTable[bottom].strterm;
int term_len = strlen(term);
memset(subs,'\0',len);
strncpy(subs,target,term_len);
int subs_len = strlen(subs);
int re = strcmp(subs,term);
if (re == 0)
{
return term_len;
}
bottom--;
}
delete[] subs;
strncpy does not add a terminating null byte if the source string is longer than the maximum number of characters (i.e. in your case, that would be if strlen(target) > term_len holds). If that happens, subs may or may not be null terminated correctly.
Try changing your strncpy call to
strncpy(subs, target, term_len-1);
so that even if strncpy doesn't add a terminating null byte, subs will still be null-terminated correctly due to the previous memset call.
Now, that being said - you could avoid using a separate subs buffer altogether (which leaks anyway in case the control flow gets to the return statement) by just using strncmp as in
while(top<=bottom) {
char* term = m_strTermTable[bottom].strterm;
int term_len = strlen(term);
if (strncmp(term, target, term_len) == 0) {
return term_len;
}
bottom--;
}

Assigning chars to a char array with +=

Currently I'm writing a rather extensive homework assignment that - among other things - reads a file, builds a binary search tree and outputs it.
Somewhere inside all that I've written a recursive method to output the values of the binary search tree in order.
void output(node* n)
{
if(n->leftChild != NULL)
output(n->leftChild);
cout << n->keyAndValue << " || ";
outputString += n->keyAndValue << '|';
if(n->rightChild != NULL)
output(n->rightChild);
}
No problem with that, but you'll notice the line outputString += n->keyAndValue << '|';, because I also want to have all the values inside a char array (I am not allowed to use strings or other more current features of C++) that I can use later on in a different method (e.g. Main method).
The Char-Array is declared as follows:
char *outputString;
This being just one of the ways I've tried. I also tried using the const keyword and just regularly building an array char outputString[]. With the version I've shown you I encounter an error when - later on in the program in a different method - calling the following code:
cout << outputString;
I get the following error:
Unhandled exception at 0x008c2c2a in BST.exe: 0xC00000005: Access Violation reading location 0x5000000000.
Any clue as to how I'd be able to build a dynamic char array, assign values to it numerous times using += and outputting it without triggering an access violation? I am sorry for asking a rather basic question but I am entirely new to C++.
Thanks and Regards,
Dennis
I'm guessing that since you can't use std::string, you also can't use new[].
You can concatenate strings with a function like this:
char *concat(const char *s1, const char *s2)
{
size_t len = strlen(s1) + strlen(s2);
char *result = (char*)malloc(len+1);
strcpy(result, s1);
strcat(result, s2);
return result;
}
This can be done more efficiently, but that probably doesn't matter for homework. And you need to check for errors, etc. etc.
You also need to decide who is going to call free on s1 and s2.
For what it is worth, the efficient version looks like this:
char *concat(const char *s1, const char *s2)
{
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
char *result = (char*)malloc(len1+len2+1);
memcpy(result, s1, len1);
memcpy(result+len1, s2, len2);
result[len1+len2] = '\0';
return result;
}
It's more efficient because it only walks the input strings once.
+= on pointers does pointer arithmetic, not string concatenation. Eventually you get way beyond your array that outputString was pointing to, and trying to print it leads to a segfault.
Since you can't use std::string, you need to use strcat along with new[] and delete[] and make sure you allocated your original array with new[].