Heap corruption when deleting a string - c++

Here is my code:
std::string readString()
{
int strLen = Read<int>();
char* rawString = new char[strLen];
Read(rawString, strLen);
rawString[strLen] = '\0';
std::string retVal(rawString);
delete [] rawString;
return retVal;
}
The first line reads the length of the string.
The second line creates a new char array (c-string) with the string length
The third line reads the string (its reading it from a file)
The 4th line adds a NULL to the end.
The 5th line creates an std::string out of the c-string.
The 6th line deletes the c-string (HEAP CORRUPTION HAPPENS HERE)
The 7th line returns the string, but it never reaches this point because of an error.
On the 6th line I get a heap corruption error:
CRT detected that the application wrote to memory after end of heap buffer.
My question may be obvious, but why am I getting a heap corruption? When I create an std::string, it should copy the string, and I should be safe to delete the c-string.
Currently, I'm suspecting that std::string is trying to access the c-string after I delete it.
Any ideas?

You're accessing past the reserved bytes for your string. You reserved strLen characters, but put a \0 at the character strLen. Counting as C arrays from 0, character strLen is at position strLen + 1, so you're putting a value outside the reserved space for the string. You should reserve strLen + 1 in the second line of your main for your code to work.

Change:
char* rawString = new char[strLen];
to:
char* rawString = new char[strLen + 1];

int strLen = Read<int>() probably only returns the length of a non-null-terminated string, and when you try to write the \0 byte to the string, you run into buffer overflow problems.
You should check what strLen is, and most likely you either have to allocate like this:
char *rawString = new char[strlen+1];
Or use the overloaded constructor of std::string(const char *, size_t n) like this:
std::string retVal(rawString, strlen);

Since arrays are 0-indexed in c++, when you create an array of size strLen and then place a 0 at position strLen, you are writing that zero one after the end of the array you allocated.

Many advices so far, but none which address the exception safety issue: how do you get rid of that potential memory leak ?
There are two ways to avoid allocating with new (and thus facing a memory leak). The first is extremely simply and makes use of a compiler extension known as VLA for Variable Length Array:
std::string readString()
{
int strLen = Read<int>();
char rawString[strLen+1]; // VLA: the length is determined at runtime
// but the array is nonetheless on the stack
Read(rawString, strLen);
rawString[strLen] = '\0';
std::string retVal(rawString);
return retVal;
}
The other is compliant with the standard: string has an internal buffer which you can access (thanks to GMan, data is not the right access method)
std::string readString()
{
int strLen = Read<int>();
std::string retVal(strLen, '\0'); // no need to allocate extra space
Read(&retVal[0], strLen); // &retVal[0] gives access to the buffer
return retVal;
}
I do believe that the last version is MUCH better. There is no longer any copying involved :)

rawString[strLen] = '\0';
Writes the NUL off the end of the space you have allocated.
If strLen is 10, then you allocate space for 10 characters, read 10 characters, and write this NUL in position 11. Ooops

Related

The strcpy_s function doesn't work in my code

This function is supposed to copy a char[] into the allocated storage. For some reason the buffer is always too small for this operation.
str(char* f) {
len = strlen(f);
txt = (char*)malloc(len); //txt is a pointer to a char
strcpy_s(txt, len, f);
}
For some reason the buffer is always too small for this operation.
You forgot to allocate memory for the null terminator. An empty string requires space for one character (the terminator). A string of length one requires space for two characters (1 + 1). A string of length len requires space for len + 1 characters.
That said:
In C, use strdup instead.
In C++, don't use strlen, malloc nor strcpy_s (nor strdup). I recommend std::string.
make sure you include cstring library

free(): invalid pointer when adding string

This code works ok:
void sendToOne(int fd, string message)
{
message += "$";
char* S = new char[message.length()];
strcpy(S, message.c_str());
write(fd, S, message.length());
}
But when I add small change:
void sendToOne(int fd, string message)
{
string msg2 = message + "$";
char* S = new char[msg2.length()];
strcpy(S, msg2.c_str());
write(fd, S, msg2.length());
}
I am getting: free(): invalid pointer error. Can you explain me why does that happen?
Your code has a buffer overrun write in it:
char* S = new char[msg2.length()];
strcpy(S, msg2.c_str());
The first line allocates enough space for the characters in msg2, but the second line copies said characters (assuming no embedded NULs) and the NUL byte at the end (a total of one byte more than you allocated). If you get unlucky, and there were no slack bytes at the end of the allocation, you'll often overwrite allocator metadata bytes preceding a subsequent allocation (or an entry in the free list); when the allocator tries to use them, it (if you're "lucky") tries to read invalid memory and dies immediately; if you're "unlucky", it happens to point to random memory that's available to your process, but probably not the right place, and you get progressively more and more corruption until everything explodes.
All that said, it's kind of silly to do this. Just write the string's data directly:
string msg2 = message + "$";
write(fd, msg2.c_str(), msg2.length());
which also avoids the memory leak you made by using new without smart pointer management or a matching call to delete[].
you need extra 1 byte to hold the null character
char* S = new char[msg2.length() + 1];
see strcpy

How to code a strcat function that works with two dynamic arrays

As we know, the strcat function concatinates one c-string onto another to make one big c-string containing two others.
My question is how to make a strcat function that works with two dynamically allocated arrays.
The desired strcat function should be able to work for any sized myStr1 and myStr2
//dynamic c-string array 1
char* myStr1 = new char [26];
strcpy(myStr1, "The dog on the farm goes ");
//dynamic c-string array 2
char* myStr2 = new char [6];
strcpy(myStr2, "bark.");
//desired function
strcat(myStr1,myStr2);
cout<<myStr1; //would output 'The dog on the farm goes bark.'
This is as far as I was able to get on my own:
//*& indicates that the dynamic c-string str1 is passed by reference
void strcat(char*& str1, char* str2)
{
int size1 = strlen(str1);
int size2 = strlen(str2);
//unknown code
//str1 = new char [size1+size2]; //Would wipe out str1's original contents
}
Thanks!
You need first to understand better how pointers work. Your code for example:
char* myStr1 = new char [25];
myStr1 = "The dog on the farm goes ";
first allocates 25 characters, then ignores the pointer to that allocated area (the technical term is "leaks it") and sets myStr1 to point to a string literal.
That code should have used strcpy instead to copy from the string literal into the allocated area. Except that the string is 25 characters so you will need to allocate space for at least 26 as one is needed for the ASCII NUL terminator (0x00).
Correct code for that part should have been:
char* myStr1 = new char [26]; // One more than the actual string length
strcpy(myStr1, "The dog on the farm goes ");
To do the concatenation of C strings the algorithm could be:
measure the lengths n1 and n2 of the two strings (with strlen)
allocate n1+n2+1 charaters for the destination buffer (+1 is needed for the C string terminator)
strcpy the first string at the start of the buffer
strcat the second string to the buffer (*)
delete[] the memory for the original string buffers if they are not needed (if this is the right thing to do or not depends on who is the "owner" of the strings... this part is tricky as the C string interface doesn't specify that).
(*) This is not the most efficient way. strcat will go through all the characters of the string to find where it ends, but you already know that the first string length is n1 and the concatenation could be done instead with strcpy too by choosing the correct start as buffer+n1. Even better instead of strcpy you could use memcpy everywhere if you know the count as strcpy will have to check each character for being the NUL terminator. Before getting into this kind of optimization however you should understand clearly how things work... only once the string concatenation code is correct and for you totally obvious you are authorized to even start thinking about optimization.
PS: Once you get all this correct and working and efficient you will appreciate how much of a simplification is to use std::string objects instead, where all this convoluted code becomes just s1+s2.
You allocate memory and make your pointers point to that memory. Then you overwrite the pointers, making them point somewhere else. The assignment of e.g. myStr1 causes the variable to point to the string literal instead of the memory you allocated. You need to copy the strings into the memory you have allocated.
Of course, that copying will lead to another problem, as you seem to forget that C-strings need an extra character for the terminator. So a C-string with 5 characters needs space for six characters.
As for your concatenation function, you need to do copying here too. Allocate enough space for both strings plus a single terminator character. Then copy the first string into the beginning of the new memory, and copy the second string into the end.
Also you need a temporary pointer variable for the memory you allocate, as you otherwise "would wipe out str1's original contents" (not strictly true, you just make str1 point somewhere else, losing the original pointer).

Manage memory C++

I have create these simple function.
char* tmp = new char[len];
strncpy(tmp,str+start,len);
int ret = atoi(tmp);
delete []tmp;
return ret;
I have a problem with memory managment.
When I read ret variable, the value is null. If I remove the instruction "delete []tmp;" the value is correct but the memory fast increase (because I don't release the memory).
Any ideas?
Thanks
From man strncpy: The strncpy() function is similar than strcpy, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
Check your str variable length and verify this null terminating condicion on strncpy
There are a few problems with atoi, one of them is that it doesn't have any kind of validation that the string you pass is really a number. Instead you might want to use strtol instead.
Also note that strncpy might not terminate the string in some cases. And that you might want to allocate one extra character (len + 1) for the terminator.
strncpy fills up the target array with '\0's once the end of the source is reached.
atoi expects a null terminated c-string, means an array of characters that ends with a '\0'.
Therefore you have to create an array with a size of len + 1, the strncpy function will the automatically null-terminate your target array.
What you could do is have the buffer be allocated from outside the function, and pass the tmp argument as an array. A better approach though, is to allocate an object. These get destructed as long as you don't use the new keyword. std::string would be perfect in this scenario.
Make sure tmp is terminated with a '\0'
Hard to tell what's wrong since str and len are not shown.
This function could be a lot simpler:
int ret = atoi(str + start);
return ret;
BTW, ret is an int and NULL is usually referred to pointers.

Memcpy, string and terminator

I have to write a function that fills a char* buffer for an assigned length with the content of a string. If the string is too long, I just have to cut it. The buffer is not allocated by me but by the user of my function. I tried something like this:
int writebuff(char* buffer, int length){
string text="123456789012345";
memcpy(buffer, text.c_str(),length);
//buffer[length]='\0';
return 1;
}
int main(){
char* buffer = new char[10];
writebuff(buffer,10);
cout << "After: "<<buffer<<endl;
}
my question is about the terminator: should it be there or not? This function is used in a much wider code and sometimes it seems I get problems with strange characters when the string needs to be cut.
Any hints on the correct procedure to follow?
A C-style string must be terminated with a zero character '\0'.
In addition you have another problem with your code - it may try to copy from beyond the end of your source string. This is classic undefined behavior. It may look like it works, until the one time that the string is allocated at the end of a heap memory block and the copy goes off into a protected area of memory and fails spectacularly. You should copy only until the minimum of the length of the buffer or the length of the string.
P.S. For completeness here's a good version of your function. Thanks to Naveen for pointing out the off-by-one error in your terminating null. I've taken the liberty of using your return value to indicate the length of the returned string, or the number of characters required if the length passed in was <= 0.
int writebuff(char* buffer, int length)
{
string text="123456789012345";
if (length <= 0)
return text.size();
if (text.size() < length)
{
memcpy(buffer, text.c_str(), text.size()+1);
return text.size();
}
memcpy(buffer, text.c_str(), length-1);
buffer[length-1]='\0';
return length-1;
}
If you want to treat the buffer as a string you should NULL terminate it. For this you need to copy length-1 characters using memcpy and set the length-1 character as \0.
it seems you are using C++ - given that, the simplest approach is (assuming that NUL termination is required by the interface spec)
int writebuff(char* buffer, int length)
{
string text = "123456789012345";
std::fill_n(buffer, length, 0); // reset the entire buffer
// use the built-in copy method from std::string, it will decide what's best.
text.copy(buffer, length);
// only over-write the last character if source is greater than length
if (length < text.size())
buffer[length-1] = 0;
return 1; // eh?
}
char * Buffers must be null terminated unless you are explicitly passing out the length with it everywhere and saying so that the buffer is not null terminated.
Whether or not you should terminate the string with a \0 depends on the specification of your writebuff function. If what you have in buffer should be a valid C-style string after calling your function, you should terminate it with a \0.
Note, though, that c_str() will terminate with a \0 for you, so you could use text.size() + 1 as the size of the source string. Also note that if length is larger than the size of the string, you will copy further than what text provides with your current code (you can use min(length - 2, text.size() + 1/*trailing \0*/) to prevent that, and set buffer[length - 1] = 0 to cap it off).
The buffer allocated in main is leaked, btw
my question is about the terminator: should it be there or not?
Yes. It should be there. Otherwise how would you later know where the string ends? And how would cout would know? It would keep printing garbage till it encounters a garbage whose value happens to be \0. Your program might even crash.
As a sidenote, your program is leaking memory. It doesn't free the memory it allocates. But since you're exiting from the main(), it doesn't matter much; after all once the program ends, all the memory would go back to the OS, whether you deallocate it or not. But its good practice in general, if you don't forget deallocating memory (or any other resource ) yourself.
I agree with Necrolis that strncpy is the way to go, but it will not get the null terminator if the string is too long. You had the right idea in putting an explicit terminator, but as written your code puts it one past the end. (This is in C, since you seemed to be doing more C than C++?)
int writebuff(char* buffer, int length){
char* text="123456789012345";
strncpy(buffer, text, length);
buffer[length-1]='\0';
return 1;
}
It should most defiantly be there*, this prevents strings that are too long for the buffer from filling it completely and causing an overflow later on when its accessed. though imo, strncpy should be used instead of memcpy, but you'll still have to null terminate it. (also your example leaks memory).
*if you're ever in doubt, go the safest route!
First, I don't know whether writerbuff should terminate the string or not. That is a design question, to be answered by the person who decided that writebuff should exist at all.
Second, taking your specific example as a whole, there are two problems. One is that you pass an unterminated string to operator<<(ostream, char*). Second is the commented-out line writes beyond the end of the indicated buffer. Both of these invoke undefined behavior.
(Third is a design flaw -- can you know that length is always less than the length of text?)
Try this:
int writebuff(char* buffer, int length){
string text="123456789012345";
memcpy(buffer, text.c_str(),length);
buffer[length-1]='\0';
return 1;
}
int main(){
char* buffer = new char[10];
writebuff(buffer,10);
cout << "After: "<<buffer<<endl;
}
In main(), you should delete the buffer you allocated with new., or allocate it statically (char buf[10]). Yes, it's only 10 bytes, and yes, it's a memory "pool," not a leak, since it's a one-time allocations, and yes, you need that memory around for the entire running time of the program. But it's still a good habit to be into.
In C/C++ the general contract with character buffers is that they be null-terminiated, so I would include it unless I had been explicitly told not to do it. And if I did, I would comment it, and maybe even use a typedef or name on the char * parameter indicating that the result is a string that is not null terminated.