Heap corruption when deleting a string

左心房为你撑大大i 提交于 2019-12-22 11:20:27

问题


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?


回答1:


Change:

char* rawString = new char[strLen];

to:

char* rawString = new char[strLen + 1];



回答2:


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.




回答3:


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);



回答4:


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.




回答5:


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 :)




回答6:


 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



来源:https://stackoverflow.com/questions/4219584/heap-corruption-when-deleting-a-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!