1

How to delete the pointer that I assign in the below code:

char* ptr;
ptr=new char(65);   // memory for one char is created and is assigned 'A'
strcpy(ptr,"asdf"); // how can string of length 4 chars are copied
delete ptr;         // why am I getting debug error of Heap corruption detected

I am using Visual C++ 2005

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Swathi Appari
  • 193
  • 1
  • 1
  • 12
  • 3
    you're overflowing heap, you get undef behavior – Mr.Anubis Jul 12 '12 at 11:20
  • may be `for i in 65 to 0 delete (ptr + i )` –  Jul 12 '12 at 11:26
  • 2
    Your comments on the code is your answer. Copying a string of 5 characters (don't forget the `'\0'`) into a dynamically allocated block of 1 character corrupts the heap. (Formally, it's undefined behavior, but heap corruption is the usual symptom.) – James Kanze Jul 12 '12 at 11:36
  • @ James Kanze, I got it now, but why this type of stuffing into small memory block is legal when we cant release memory. And how to deal with such cases – Swathi Appari Jul 12 '12 at 11:37
  • 2
    @SwathiAppari, when you pass `strcpy` a pointer, the compiler has no idea what's the size of the pointed buffer. So it can't prevent you from making such mistakes. `strcpy` itself also has no idea what's the buffer size, and can't complain. It is up to you to make sure you don't make such mistakes. Since you're using VS, there's a `strcpy` variant called [strcpy_s](http://msdn.microsoft.com/en-us/library/td1esda9(v=vs.80).aspx), which also takes the buffer's size. Then, it fails if the buffer is too small, without overflowing it. – Eran Jul 12 '12 at 11:43
  • 2
    @SwathiAppari: It's *not* legal, it's just that nobody tells the program that it's done something bad and leaves it to suffer the consequences instead. C++ is like that. Remember the old saying: "With great power comes great responsibility, great confusion and grating syntax." – molbdnilo Jul 12 '12 at 12:52

5 Answers5

7

You're allocating a single char instead of an array. Use:

char* ptr;
ptr=new char[65];
strcpy(ptr,"asdf");
delete[] ptr;

As it is now, you're writing the first a to the allocated char, and the rest on some arbitrary memory that was never allocated to you. The runtime detects that (on debug build), and complains.

Making my comment to the question part of my answer:

C++ doesn't have any mechanism to identify the potential error in the question's code. The only way for a compiler to know the size of the buffer that is passed to strcpy is using static analysis, and that may or may not work. But even if it does, the compiler doesn't know the semantics of strcpy. So at compile time, it can't warn you about the error.

Now, when the buffer is passed tostrcpy at runtime, strcpy has no way to tell how large is that buffer. So it just assumes the caller provided a suitable buffer, and goes ahead with the copy. If you're lucky, overflowing the allocated buffer will cause an immediate crash due to a write to unallocated page. If not, you'll get a memory corruption.

The error you do get is the result of a mechanism used on debug builds: the memory manager allocates a few more bytes than what you ask, and writes a special pattern onto them. Then, when the allocated memory is freed, it checks whether that pattern still exists. If not, it complains the user's code has written onto them. In release builds, you don't have those extra checks, and such bugs may cause a corruption without being noticed.

The only way to avoid such cases is to write safer code:

  1. Use higher-level constructs like std::string. They do the memory management for you, and save you from having to deal with low-level string functions.
  2. Use Microsoft's (non-standard) safe variants - strcpy_s, for example. Those functions take the size of the buffer as well, and fail if it is insufficient - without doing any damage.
  3. Use (standard) strncpy, pass the buffer's size as the last argument, and check the return value to see how many chars have been copied. As with the previous suggestion, specifying a wrong buffer size will still cause damage.
  4. Bear in mind that if you want to shoot your own toes, C++ will gladly hand you a down-pointing gun. Dealing with raw buffers, pointers and low-level string functions has to be done with care. The language will not save you from your own mistakes.
Eran
  • 21,632
  • 6
  • 56
  • 89
  • 1
    (Repost) He didn't mean to create an array of 65 characters since he said "memory for one char is created and is assigned 'A'" in the code comments. – Desmond Hume Jul 12 '12 at 11:24
  • @DesmondHume, the purpose of the code is a bit unclear (why allocate a single char and write an array of chars onto it?). But I do explain why he gets that error, as he asks in the last row's comment. – Eran Jul 12 '12 at 11:27
4

Because you corrupted the heap by trying to stuff 4 characters "asdf" (actually 5 if count null terminator) into a memory block that is only capable of 1 character by doing this:

strcpy(ptr,"asdf");

Update:

You should allocate as much memory as needed (or more). If you need to copy a 4-character string into a memory block you should make sure that that the memory block will be large enough to keep it, so, in your case, you should use

ptr=new char[5];

to allocate 5 chars (4 chars of the string + 1 null terminator every string should have at its end), and to release the allocated memory, you should use

delete[] ptr;

[] means that you want to delete an array of chars, not just one char.

Desmond Hume
  • 8,037
  • 14
  • 65
  • 112
  • I got it now, but why this type of stuffing into small memory block is legal when we cant release memory. And how to deal with such cases – Swathi Appari Jul 12 '12 at 11:35
  • 1
    @SwathiAppari No, it's not legal. If it was, Visual C++ would not complain about it. And in such cases you should allocate as much memory as needed (or more). If you need to copy a 4-character string into a memory block you should make sure that that the memory block will be large enough to keep it, so in your case, you should use `ptr=new char[5];` to allocate 5 characters (4 chars of the string + 1 null terminator every string should have at its end), and to release the allocated memory, you should use `delete[] ptr;` (`[]` means that you want to delete an array of chars, not just one char). – Desmond Hume Jul 12 '12 at 11:44
  • @SwathiAppari Updated the answer accordingly. – Desmond Hume Jul 12 '12 at 11:47
1

That's actually wrong. You want:

ptr=new char[65];   // memory for one char is created and is assigned 'A'
strcpy(ptr,"asdf"); // how can string of length 4 chars are copied
delete[] ptr;   

better:

char ptr[65];
strcpy(ptr,"asdf");

best:

std::string str("asdf");
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • Although your recommendation of std::string is fine, the whole answer does not explains the issue. The problem is the use of strcpy on a buffer which is too small. – swegi Jul 12 '12 at 11:26
1

This is a typical case of memory corruption. Heap to be specific. ptr has just 1 byte allocated and you are doing a string copy operation overflowing that 1 byte.

Your program may not necessarily crash immediately, but would result in random crashes or undefined behavior.

Jay D
  • 3,263
  • 4
  • 32
  • 48
1

First you allocated ptr with a single byte. and assigned 'A' to it.

And then tried to copy string of size 5 to ptr using strcpy.

You might be wondering why it didn't crash at the strcpy call itself. The reason is strcpy does not perform any validation on the size of allocation and hence causing undefined behavior as a result of buffer overflow.

Refer: Segmentation fault in strcpy

char* ptr;
ptr=new char[5];   // I see no point in assigning 'A' as you replace it in next statement.
strcpy(ptr,"asdf");
delete[] ptr;         // delete[] is used as memory is allocated for arrays of elements.

Also, In Visual Studio 2005, you can use the secure alternative for strcpy, strcpy_s.

Refer: strcpy_s, wcscpy_s, _mbscpy_s

Community
  • 1
  • 1
Ragesh Chakkadath
  • 1,521
  • 1
  • 14
  • 32